CHAPTER 17

ABOUT THE WINDOWS CLIPBOARD.

OVERVIEW:

First, I pose the question: what happens to text when you highlight it, and then click 'copy', close the program, open another window, and then paste the copied text into the new window?

Obviously, the text data cannot be stored within the program associated with an open window, since it is still available even after the window has been terminated. Clearly, the answer must be that the data is stored by the operating system itself. This is done in what is called the 'Windows Clipboard', which is a special temporary data storage application belonging to the operating system itself.

Data stored in the Windows Clipboard can be transferred from one application to another, or from an application back into the same application, as when a paragraph of text is cut from its current position and pasted back into a different position in the same text. The clipboard is for data storage of any type, text, graphics, or whatever.

What follows here is an account of how to use the clipboard, as this involves using a proper sequence of API function calls in order to ensure that the clipboard works properly, or at all.

REGISTERING A CLIPBOARD FORMAT:

The Windows Clipboard documentation will specify that you must first of all 'register a format' for your data with the Clipboard.

The concept of a 'format' has to do with the concept of different file types, since different files store different kinds of data, such as plain text, or formatted, rich text, or graphics, or whatever.

At first sight, if you are wrestling with instructions in the documentation, the concept of registration might look like something of a puzzle. How, you may ask, can I instruct the Clipboard to recognise a format, or data type? Do I, for example, have to send a file header to the Clipboard to describe the file format for the data, and is there a Clipboard file header API to tell the Clipboard that this is formatting information? In fact, there is no such puzzle, and nothing so complicated. In reality, the Clipboard will know nothing at all about the formatting details of your data. The reason for the so-called registration of a format is as follows:

To take an example, suppose you attempt to paste data from the clipboard into your program. The question arises as to what kind of data you are trying to paste. You could be trying to paste a bitmap into a text file, for example, or vice versa. You could be trying to paste any kind of data that is formatted differently from the formatting appropriate to your program. Here we have the reason for 'registering' formats with the Clipboard. It simply enables your application to test whether the data to be pasted is data with a format that your application can use. It is necessary only that your type of data have an identification number registered with the Clipboard which your application can check, and it is not necessary for the Clipboard to know anything further about it.

Whenever data of any type is transferred to the Clipboard from any application, an appropriate identification number will be associated with its particular format type and, before your code tries to paste the data again, the identification number will tell your program that the data is from the same type of file and that it will therefore be able to process the data.

There are, however, a few default formats where the Clipboard does actually have the formatting details

already written into it.

These include a simple plain text format and a couple of bitmap formats.

In the case of these formats, the Clipboard window, if it is opened, can display the data and can also perform some data conversions. For custom formats, the Clipboard window cannot display the data, since the formatting details are not written into it. Nor is there any provision for such formatting details to be written into the Clipboard, as the default formats are pre-written into the Clipboard source code. If the Clipboard window is opened to display data with a custom format, it will display a message indicating that the data is in an 'unknown' format.

From the above it is clear that the Clipboard can transfer any kind of data whatever, and therefore identification numbers or labels are needed to distinguish one kind of data from another. The identification of your data must be uniquely recognisable to Windows.

Suppose, for example, your program places data on the Clipboard, and your program window is then closed; then, later, another window is opened, and the user tries to paste the data from the Clipboard into the new window - how does the Clipboard tell your program that the format identification number belongs to your type of program?

The answer is that you will have to create a format identification name text string in the data section of your program. The address of this string is passed to Windows when registering the format with the Clipboard, whether sending data to or receiving data from the Clipboard. An example could be something like:

CLIPBRD.FormatName db "calculator1",0

if you created some kind of calculator application. The name can be anything you like.

Windows thus associates the format identification number with your format name text string, which is always the same. In other words, if the format name string has been previously passed to Windows, Windows associates the previous identification number with it, so that the identification number remains the same.

ASSIGNING MEMORY TO THE CLIPBOARD:

Apart from the matter of identifying types of data, there remains the problem of where the Clipboard is to store the data assigned to it.

The Clipboard must have a memory block assigned to it, as it does not have any permanent block of memory of its own. This would not make sense, since the amount of data sent to the Clipboard at any one time is completely unpredictable. This memory cannot be a memory block belonging to the application, either, but must be owned by the Clipboard itself, since the Clipboard data must be available to be independently accessed by different applications.

Thus an independent, or 'globalised' memory block must be created, using the GlobalAlloc API function. This is independent of the Clipboard, and is simply a block of 'globalised' memory; that is, a block of memory that can be globally accessible within the system as a whole. This is created as follows:

api GlobalAlloc,GMEM_MOVEABLE,[CL.DataSize]
mov [CLIPBOARD.DataHandle],eax

The [CL.DataSize] parameter specifies the size of the memory block, which corresponds to the size in bytes of the data to be uploaded to the clipboard. The flag GMEM_MOVEABLE must be included, and means that the block of memory can be moved around by

the Windows operating system in the usual manner in which it manages memory that is not currently being accessed. Since the address of the block of memory can be changed, the system keeps track of it via its identification number, or handle, saved as [CLIPBOARD.DataHandle].

Having created a globalised block of memory, your code will have to transfer the intended Clipboard data into it, for which purpose it is necessary to obtain the address of the memory block. Since, the memory is moveable, it must first be 'locked', or made temporarily immovable, so that you can get a fixed address in order to move your data into it. The GlobalLock API function locks the memory, identified by the its handle, and returns its address in eax, as follows:

api GlobalLock,[CLIPBOARD.DataHandle]
mov [CLIPBOARD.DataAddress],eax

The next step is to feed the data, intended for the Clipboard, into this memory block., and then hand it over into the ownership of the Clipboard. The whole operation requires a specific sequence of API function calls.

These, including the above memory allocation code, are as follows:

api GlobalAlloc,GMEM_MOVEABLE,[CL.DataSize]
mov [CLIPBOARD.DataHandle],eax
api GlobalLock,[CLIPBOARD.DataHandle]
mov [CLIPBOARD.DataAddress],eax
call CLIPBOARD.DataUpload
api RegisterClipboardFormat,CLIPBOARD.FormatName
mov [CLIPBOARD.FormatHandle],eax
api OpenClipboard,[WINDOW.Handle]
api EmptyClipboard
api SetClipboardData,[CLIPBOARD.FormatHandle],[CLIPBOARD.DataHandle]
api GlobalUnlock,[CLIPBOARD.DataHandle]
api CloseClipboard

CLIPBOARD.DataUpload refers to your own procedure, whatever code it might contain, which is called for transferring the data to the memory block.

In order to hand data over to the Clipboard, the data format must first be registered, as mentioned before, by giving it a name string.

CLIPBOARD.FormatName is the address of the array where the string is defined. This address is passed as a parameter in a call to the RegisterClipboardFormat function, which returns a handle to the registered format.

This format handle is now the identification number assigned by the operating system to your type of data.

The Clipboard itself must next be opened and emptied, since your application cannot temporarily gain 'ownership' of, and upload access to, the Clipboard unless it has been emptied. Only after the Clipboard has been emptied can the data be assigned

to it by the SetClipboardData function.

Note that the memory block, which was previously locked, must be unlocked, and must not be left in a locked state after it has been handed over to the clipboard. I have found that it doesn't appear to matter whether the GlobalUnlock function is called before or after calling SetClipboardData.

Finally, the clipboard is closed, and then becomes the complete owner of the data, which can be accessed by any application.

The above is the code that transfers data to the Clipboard as, for example, when a user clicks the left mouse button in a 'copy' or 'cut' menu item.

If the user clicks the left button in a 'paste' menu item, a generally similar sequence of API function calls is involved in downloading data from the clipboard, but there are also significant differences, as follows:

api RegisterClipboardFormat, CLIPBRD.FormatName
mov [CLIPBRD.FormatHandle],eax
api OpenClipboard,[WINDOW.Handle]
api IsClipboardFormatAvailable,[CLIPBRD.FormatHandle]
cmp eax,No
je near .exit_gdfc
api GetClipboardData,[CLIPBRD.FormatHandle]
mov [CLIPBRD.DataHandle],eax
api GlobalLock,[CLIPBRD.DataHandle]
mov [CLIPBRD.DataAddress],eax
api GlobalSize,[CLIPBRD.DataHandle]
mov [CLIPBRD.DataSize],eax
jmp.if.d '=',[CLIPBRD.DataSize],0,.exit_gdfc
call CLIPBOARD.DownloadData
api GlobalUnlock,[CLIPBRD.DataHandle]
.exit_gdfc:
api CloseClipboard
ret

The RegisterClipboardFormat function is called, even though this is done in the context of a download of already registered data. This is because this function also returns the handle of already registered data, and the system does not create a new handle for an already registered format name.

After opening the Clipboard, the function, IsClipboardFormatAvailable, is called to test whether or not data in that format is on the Clipboard. If no data in that format is present, the code jumps to the exit, and closes the Clipboard. If data in that format is on the Clipboard, the GetClipboardData function returns a handle to it. Then the GlobalLock function then locks it and returns the address of the memory block, so that the data can be accessed.

GlobalSize returns the size, in bytes, of the data in the memory block.

CLIPBOARD.DownloadData is the name of a procedure that represents the program's own data transfer code. After this procedure code has copied the data from the Clipboard, and stored it in the programs data section, the memory block is again unlocked, and still belongs to the Clipboard, along with its data, and then the Clipboard is closed.

Sometimes an application may be able to use different kinds of data in more than one format. In this case, it is necessary to test the Clipboard to see if contains data in any of the usable formats. In such a case, it is possible to give the Clipboard a list of usable formats and ask if any format in the list is

available.

To do this, the GetPriorityClipboardFormat API function is called instead of the function, IsClipboardFormatAvailable.

The code shown below illustrates the use of the GetPriorityClipboardFormat function.

The CLIPBRD.FormatHandles parameter in the GetPriorityClipboardFormat function call is the address of a list of format handles, the parameter 2 indicating that, in this case, there are two format handles in the list.

The function returns the available format handle in eax, or returns 0, if the Clipboard is empty, or 0ffffffffh (-1) if its data is not in any of the formats in the list. In either of these latter cases, the code jumps to the exit and closes the Clipboard. Otherwise it proceeds to access and download the data as before.

The start.if/end.if code sequence tests the variable, CLIPBOARD.FormatHandle, to see which format is available, and calls its own download code procedure, CLIPBOARD.Download.1, if the data is format 1 type data, or CLIPBOARD.Download.2, if it is format 2 type data.

The if.d '=' HLA macro means: if (dword values) [CLIPBRD.FormatHandle] is equal to [esi], then call CLIPBOARD.Download.1, or if it is equal to [esi+4], then call CLIPBOARD.Download.2.

api RegisterClipboardFormat, CLIPBRD.FormatName
mov [CLIPBRD.FormatHandle],eax
api OpenClipboard,[WINDOW.Handle]
api GetPriorityClipboardFormat, CLIPBRD.FormatHandles,2
mov [CLIPBRD.FormatHandle],eax
jmp.if.d '=',[CLIPBRD.FormatHandle],0,0ffffffffh, .exit_gdfc
api GetClipboardData,[CLIPBRD.FormatHandle]
mov [CLIPBRD.DataHandle],eax
api GlobalLock,[CLIPBRD.DataHandle]
mov [CLIPBRD.DataAddress],eax
api GlobalSize,[CLIPBRD.DataHandle]
mov [CLIPBRD.DataSize],eax
jmp.if.d '=',[CLIPBRD.DataSize],0,.exit_gdfc
mov esi,CLIPBRD.FormatHandles
start.if
if.d '=', [CLIPBRD.FormatHandle], [esi], [esi+4]
then.call CLIPBOARD.Download.1, CLIPBOARD.Download.2
end.if
api GlobalUnlock,[CLIPBRD.DataHandle]
.exit_gdfc:
api CloseClipboard
ret

                  Part I: Part I Introduction
                  Chapter 1: Binary numbers, code, and procedures
                  Chapter 3: Assembly Language
                  Chapter 4: Assembly Language Code example
                  Chapter 5: Macros and HLA
                  Chapter 6: HLA code example
                  Chapter 7: The Windows operating system
                  Chapter 8: Data Structures
                  Chapter 9: How to Create a Windows Program
                  Chapter 10: How to Create an Exe File
                  Chapter 11: Structured Programming and OOP
                  Part II: Part II Introduction
                  Chapter 12: Debugging a Windows Program Code
                  Chapter 13: Painting the Window Client Area
                  Chapter 14: Creating Window Menus
                  Chapter 15: How to Create Toolbars
                  Chapter 16: How to Create Popup Menus
                  Chapter 17: About the Windows Clipboard
                  Chapter 18: How to Create Bitmaps
                  Chapter 19: Icons and the Ico Format
                  Chapter 20: Common Dialog Boxes
                  Chapter 21: Working with Files
                  Chapter 22: Scrollbars and Scrolling
                  Chapter 23: How to Send Data to the Printer
                  Chapter 24: Miscellaneous Topics

©Alen, June 2014
alen@alenspage.net


Material on this page may be reproduced
for personal use only.