Data handlers allow you to define
custom handling for copy-and-paste operations involving files of a
given type. Normally, when you select a file and press Ctrl-C or
select Copy from the Explorer menu, the shell copies the name of the
file using the CF_HDROP
format. This is evident in
the clsDropFiles class that we used to implement the
IShellExtInit::Initialize
and
IDropTarget::Drop
methods in Chapter 7. But what if we want to change this behavior
for our file type? Take a bitmap file for instance. What if, instead
of copying the file, we want to copy the actual image contained
within the file? Then you would be able to highlight the file in
Explorer and make it available to any program that knows how to
handle CF_BITMAP
information (Microsoft Paint,
Adobe Photoshop, etc.). Or what if we want to copy information from
the file, say in CF_TEXT
format, to the clipboard?
We might want to copy its dimensions, for example, or the color depth
of the file. This would allow us to select a file in the shell, press
Ctrl-C, and copy pertinent information directly from the file into
other programs like Microsoft Word or Excel.
Data handlers are required to implement two interfaces. These
interfaces are IPersistFile
and
IDataObject
. The IPersistFile
implementation serves the same purpose it did for our icon handler
and drop handler. We will just implement Load
to
get the name of the file in question.
We have used
IDataObject
before, but we have never implemented it. Admittedly, when
IDataObject
was last discussed (see Chapter 4), all you got was a really glossed overview of
the interface. In this chapter, we will talk more about this
interface and get a little better idea of how it works. But by no
means will the discussion be complete. To write a data handler, we
need to implement only three of nine available methods. But after we
implement these methods, you should be able to explore the rest of
IDataObject
with better understanding.
Our data handler will be fairly simple, although the implementation
is somewhat involved. When a .rad
file is copied
in the shell, the data handler will determine the type of animal
represented by the file and build the string “The
(animal name) is on the clipboard.” This
string is then made available to any program that allows for text
transfers (CF_TEXT
format) over the clipboard via
the Paste command. Figure 8.1, for example, shows a
string generated by the data handler for .rad
files that has been pasted into Notepad.
Data handlers are activated when a file is copied in the shell. Selecting Copy from Explorer’s File menu, selecting Copy from the context menu of the file object itself, pressing Ctrl-C, or pressing Ctrl-Insert will all initiate a registered data handler if one exists. To do this, the shell looks under the following key:
HKEY_CLASSES_ROOT {application identifier} shellex DataHandler
Once loaded, the shell passes the name of the file being copied to
the data handler via the IPersistFile::Load
method. We’ve seen this functionality a few times already (icon
handlers and drop handlers). Nothing’s different here. Like
before, the filename can be stored in a private class member until it
is needed at a later time.
The shell then calls IDataObject::QueryGetData
repeatedly in an attempt to figure out all of the formats a data
handler can use. Each time QueryGetData
is called,
a pointer to a FORMATETC
structure is passed in by
the shell. The FORMATETC
structure describes the
format of the data that will be involved in the data transfer: text,
bitmaps, metafiles, etc. We’ll talk about this structure later.
Every
time the shell calls QueryGetData
, it is saying,
“If I call GetData
with this format, will
the call be successful?” In other words, will
GetData
be able to provide me the data described
by this FORMATETC
structure? The
QueryGetData
method is provided by data objects
(objects that implement IDataObject
) as a way for
the caller to determine what formats the data object can provide.
However, the fact that the shell calls this method seems a little
odd, because IDataObject
has another method called
EnumFormatEtc
.
EnumFormatEtc
provides a way for the shell to retrieve all of the formats that are
supported by the data handler. In fact, it is this method that the
shell calls right after QueryGetData
. This is
strange behavior because, rather than ask what formats a data object
supports, the shell could just ask for the
formats.
After the shell has received all
of the valid formats that the data object supports, it will then call
IDataObject::GetData
to retrieve the data.
Whatever this “data” happens to be is completely
arbitrary. The data handler can provide whatever it wants when
GetData
is called. For instance, the example for
the chapter will retrieve the name of the animal inside of a
.rad
file and create a string that says
“The (animal name) is on the
clipboard.” We could have just as easily provided a bitmap of
the animal or a short biography of the animal’s life thus far.
The point is that whatever you want to provide is up to you, and
GetData
is where the work gets done.
So after GetData
has been called, the handler is
out of the picture. But the show is not over . . .
At this point (with regard to our chapter example), the Paste menu of
any program supporting text
(CF_TEXT
) clipboard transfers will be active.
Programs supporting CF_TEXT
include Notepad and
Microsoft Word. When Paste is selected from the menu of one of these
programs or a similar program, the contents of the clipboard are
transferred to the application.
Programs supporting formats other than CF_TEXT
,
such as Microsoft Paint, would display a grayed out Paste menu.
18.191.236.255