OLE for Idiots - DOC by maclaren1


									#   OLE for Idiots: A Is for Attitude
Herman Rodent
Microsoft Developer Network Technology Group

Created: June 22, 1993

Click to open or copy the files in the TEXTBOX sample application for this technical article.

Does the pile of documents on your desk about Object Linking and Embedding (OLE) version
2.0 scare you? Do you hate the idea of having to learn C++? Is your manager getting a little
pushy about progress on the OLE implementation you haven't started yet? When I first looked
at OLE 2.0, it seemed very complicated and overwheIming, and I thought that maybe the time
had come for me to take up woodworking for a living. If that's how you feel, read on.

This is the first in a series of articles on implementing OLE 2.0 in your applications and covers
some basic requirements that must be understood before any OLE work can take place. The
remaining articles in the series will cover:
•    Using structured storage.
•    Creating a minimal container application.
•    Adding in-place activation to a container application.

Some time back I got hold of an early copy of the specification for Object Linking and
Embedding (OLE) version 2.0. The spec ran to about 300 pages of dense techno-stuff in a
small typeface. Gripping reading for nerds of all ages. My first impressions were that it's way too
complicated to learn or be likely to work properly and that the documentation had no
information at all about how to implement it. I decided to shelve the documents for a later date.

Since then, newer, fatter specs have come my way, each time replacing the volume on the
shelf. With the advent of the second beta of OLE 2.0, I installed the software for a quick look
and saw many samples that all "sort of" worked, as well as a bunch of test tools. Obviously, the
product was getting a little nearer release to the masses. A draft copy of the Object Linking and
Embedding Programmer's Reference, Version 2 came my way—more dense pages of
fascinating information. And then came the great sample, OUTLINE. I decided to print it out on
the aging HP® LaserJet® printer in my office, and it went right through an entire pack of 8.5-
by-11-inch paper—we're talking about 30,000 lines of text here!

Then came a draft of the first six chapters of Kraig Brockschmidt's fine, unpublished book on
OLE, Inside OLE 2, and shortly after, the OLE 2.0 Developers Conference in Seattle,
Washington (May 3-5, 1993). I read all the documents, attended the conference, read Kraig's

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                 4/29/2010       1
book, read some of the documents again, and thought, "There's no way to put it off any
longer—I'm going to have to write some code." But where to start? That's the Big Question.

I began my own investigation by attempting to leap right in and create a container application. I
made two discoveries while failing to achieve this apparently simple goal. I discovered first that
OLE is something you add to a completed application (or at least to one that is fully designed
in the first place), and second, that in order to call the OleCreate API, you need two things I
didn't have: a client site and a pointer to a storage object.

So far as I was aware, a client site is where your customers work. Storage objects I knew
about—after all, I'd read hundreds of pages of OLE documents discussing them. Mind you, I
had no idea how to get a pointer to one.

I decided to back up a bit and start again. What I did was create a complete application (albeit
a simple one) that has file I/O, Clipboard support, and so on. Then I slowly added OLE
functionality to that application. The result is a series of applications and articles that I hope will
help guide you quickly and simply through the OLE forest.

The first article looks at the base application, devoid of any OLE entanglements. The second
article adds structured storage from OLE 2.0; the third turns the application into a simple

Be aware that this series of articles is in no way a replacement for the OLE documentation,
Kraig's book Inside OLE 2, or any other source you might have—it's simply a guide to getting
started with an implementation of OLE 2.0 in your application.

Designing for OLE
You cannot implement any OLE code without having at least a fully designed application and,
preferably, a partially (or even fully) implemented one. I know this because I wasted a great
deal of time trying to see how I could play with OLE and its features without doing any real

The other major thing to realize is that you can't add OLE to just any application. The
application has to deal with displaying objects of some sort or other for it to make any sense to
add OLE to it. This isn't quite true, because (as I'm sure some of you realize) OLE provides a
structured storage system that can be used as a stand-alone feature, and it also provides an
automation feature—rather like DDE's Execute command—which could also be seen as a kind
of stand-alone feature. Nonetheless, the main reason for OLE's existence is linking and
embedding objects, and if we want some of this action, we are going to have to provide an
application to link them to or embed them in.

A major feature of all the OLE demonstrations I have seen is the highly complex user interface
required to support in-place activation. My own experience of creating Windows-based
applications suggests that about 75 percent of the programming effort goes into the user
interface and the remaining 25 percent goes to make the application do whatever it does for a
living. Implementing OLE is in keeping with this—there is a lot of user interface work to do. To
help out here, the OLE team produced a user interface DLL that is shipped as source code
with the OLE 2.0 Software Development Kit. This provides almost every dialog box you will
need in your implementation and will greatly contribute to a standard look for the world's future
OLE applications. This standardization in appearance is something the users should be very
happy about. In my efforts to show you how you can implement OLE, I will always try to do as

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                   4/29/2010         2
little work as possible, so the user interface you see in my samples is as simple as I can get
away with. What this means to you is that I might implement only one feature of a set in order
to keep the code simple and clean. I leave it to you to research the remaining members of the
set and implement them. So although my user interface will win no prizes with the users, I
hope you'll see my simple code as an attempt to make things easier for you to understand.

The TEXTBOX Application
For my base application I needed something that would make sense to add OLE to and would
have just enough features so that it could be expanded to use a reasonable amount of the OLE
system. I decided to implement a small application that shows blocks of text in rectangular
regions of the client area of the application's main window.

The Design
TEXTBOX only allows a single document to be open at any one time, which requires much
less code than for a multiple-document interface (MDI) application. The text blocks can be
created from a text file or from a Clipboard CF_TEXT object. Each object is resizable, and a
colored border drawn around an object indicates that it is the currently active object. Figure 1
shows a screen shot of the TEXTBOX application with several objects displayed.

Figure 1. The TEXTBOX application

TEXTBOX also maintains an insertion point that has a cross for a cursor. The currently active
object can be moved by clicking inside its display area and dragging it. It can also be resized
by clicking and dragging any of its four borders. The behavior of the user interface is not all that
it might be, but it is enough to provide adequate functionality without too much code.

Each object has size, position, and content information. All of the objects can be saved in a file
together with the size of the main window so that a complete scene can be reloaded at a later

How It Was Built

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                 4/29/2010        3
When I created TEXTBOX, I had no real idea of how I might add OLE functionality to it and so
designed it in a way I thought would keep it as simple as possible. Here are the steps I took to
create it:
1. Start with a template. In this case I used my own W16APP, which is on the Developer
   Network CD.
2. Design the structure definition for the object and write the list management functions.
3. Create the Insert Object dialog box for files with the .TXT extension.
4. Add Clipboard copy and cut capabilities for CF_TEXT format.
5. Add Clipboard support for the Text Box Object private format.
6. Add Clipboard paste capability.
7. Create the code for resizing the border.
8. Design the file format and write the File New, File Save, and File Load functions.
9. Add minimal printing support.

All this took about three days to do.

This might seem like a lot of work and in some ways it should seem so. After all, I said earlier
that we want to add OLE to an already complete application—at least completely designed. So
what we have now is an application that supports some form of object display and has
Clipboard support, a File Save/Load feature, and some degree of user interface in the form of
drag and resize.

Actually, a lot of the work was very easy, the bulk of the code coming from the W16APP

The following sections give some details of the implementation.

A Note About the Code
In almost all of my code samples, I generally ignore whether a pointer is near, far, or huge, and
simply name it as a pointer. So, for example, a pointer to a bucket would be named pBucket
rather than npBucket, lpBucket, or hpBucket. As we move toward the happy days of 32-bit,
flat-memory-model, Windows-based programming, I hope this simpler style will become more

Oh, No—Not Objects!
If you read the OLE documentation (and I hope you will, if you haven't already), you will find
some considerable discussion about objects. In fact, almost all of the existing publications
dealing with OLE begin with a discussion about objects in some way or other. I'm going to take
a more radical approach and not bother. After all, what is left to say about them? The
TEXTBOX sample application defines a structure called OBJECT, but this is simply where I
keep the information about each of the text regions on the screen. I could just as easily have
called it AARDVARK, which is a nice name, albeit a bit silly for an object. (Smile—this is what
passes for humor here at MSDN Central.)

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                4/29/2010       4
The other aspect of the current set of OLE documents worth mentioning is that they describe
the code-writing process as if you were implementing the application in C++. To be fair, the
sample code that accompanied the OLE 2.0 Beta release was all in straight C, rather than
C++, but the code is written to look and feel like C++. I'm not a C++ programmer and neither
are 85 percent of those of you reading this, so all my samples are in C. If you are going to be
doing a lot of OLE work, now might be a good time to consider learning C++ because, despite
the fact that (as I will demonstrate) you can implement OLE support in C, it looks a lot easier to
implement it in C++ if you are familiar with the language. My mission here is to get you started,
though, so we'll stick to straight C and leave the object-oriented approach to the textbooks
rather than use it in the code.

The TEXTBOX application defines a structure to keep track of the data associated with each
text rectangle displayed. Here's the structure as defined in GLOBAL.H:

 #define DEFAULT_OBJ_WIDTH               100
 #define DEFAULT_OBJ_HEIGHT              75

 typedef struct _OBJECT {
     struct _OBJECT FAR *pNext;                //   Pointer to the next one.
     LPVOID pInfo;                             //   Pointer to its info.
     RECT rc;                                  //   Container rectangle.
     UINT uiSize;                              //   Size of the info.
     BOOL bSelected;                           //   Is it selected?
     UINT uiType;                              //   CF_TEXT, and so on.

The application maintains a linked list of these objects. The global variable gpObjList points to
the top of the list.

The file OBJECT.C contains several functions that deal with the OBJECT structures. Table 1
lists the functions and gives a brief description of each one.

Table 1. Object Management Functions in OBJECT.C

Function                   Description

CreateObj                  Creates a new object.

DeleteObj                  Deletes an existing object.

RenderObj                  Renders the image of an object.

InsertObjCmd               Processes the Insert Object menu item.

HitTestObj                 Tests for a mouse hit inside an object.

SelectObj                  Shows an object in the selected state. Deselects all other objects.

BringObjToTop              Brings an object to the top of the list making it the most visible (on

AppendObj                  Appends an object to the end of the object list.

UnlinkObj                  Removes an object from the object list without deleting it.

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                 4/29/2010        5
SizeBorderHitTestObj      Tests for a mouse hit in the size border area of an object.

In designing and implementing these functions, I tried to keep in mind that I would be altering
them to deal with OLE objects at some point. However, with no experience to go on, predicting
what changes would be required turned out to be very difficult.

Clipboard Support
The TEXTBOX application supports two Clipboard formats: CF_TEXT and a private format
called Text Box Object. (There's that word object again.) Why two formats? I wanted to do
something really simple to get Clipboard support working early, so I chose to implement
CF_TEXT first. The CF_TEXT format lets you copy or cut the text from the currently selected
rectangle to the Clipboard. Testing this was easy—you simply used the Clipboard viewer to see
the result of the cut or copy operation. Incidentally, the reason you can only select one
rectangle at a time in the application is to keep the Clipboard support as simple as possible.

The problem with CF_TEXT was that only the text got copied, which meant that if it were
pasted back, no information about the size or position of the rectangle would be available. The
private format, Text Box Object, was designed to provide not only the text content of an object,
but also the size and position of the object. The data copied to the Clipboard consists of an
OBJECT structure followed immediately by the text data as shown in Figure 2. Since the
Clipboard viewer can't display this private format (it has no way to understand it), I had to
implement paste support next so that I could test the format.

     OBJECT struct


Figure 2. The Clipboard data format, Text Box Object

When the Cut or Copy command is chosen, the application copies both the Text Box Object
format and the CF_TEXT format data to the Clipboard.

The paste operation looks in the Clipboard for the private Text Box Object format first and then
for the CF_TEXT format. In general, an application should always look for a format that gives as
much information as possible and only if none are present should it use one of the more
generic formats, such as CF_TEXT.

All of the Clipboard support is located in the CLIP.C module, which contains nothing out of the
ordinary, so I will not reproduce the code here.

Code for Dragging and Resizing
The code to allow the currently selected rectangle to be dragged and resized is contained
mostly in the main window message handler in MAIN.C. Two helper functions, HitTestObj and
SizeBorderHitTestObj, are contained in the OBJECT.C module. These functions detect
mouse hits in the object rectangle and size border regions, respectively.

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC               4/29/2010        6
The code for dragging and resizing the rectangles is deliberately rather simplistic and,
consequently, provides a somewhat odd feel to the user. I considered it important to include
dragging and resizing because I wanted to see what was going to be involved in supporting it
with OLE objects later on.

File Open and File Save Support
The TEXTBOX application can save the set of objects and the current size of the window in a
private file format. These files can subsequently be reopened using the File Open command.
The file format consists of a header block containing an identifier tag and information about the
size of the main window, followed by a data block for each object. The object data blocks are
the same format as the Text Box Object Clipboard format and consist of an OBJECT structure
followed by a NULL-terminated text string. Figure 3 shows an example of a file structure where
two objects were saved.

   FILEHEADER struct
   OBJECT struct
   Text string
   OBJECT struct
   Text string

Figure 3. A TEXTBOX file containing two text rectangle objects

When a file is opened, the header is read and then objects are read until the end of the file is
encountered. There is no object count in the header. I considered a more complex file format,
but again decided to keep it as simple as possible to reduce the support code and also
because I was curious to see how simple a format could be used to store the OLE object data
when we eventually reached that stage of the development.

The printing support in TEXTBOX is very rudimentary. It uses the MM_ISOTROPIC mapping
mode to retain the aspect ratio of the window image and then scales the window rectangle to fit
the paper size. The result is that the relative shapes of the rectangles look right, but the text
layout is different from what appears on the screen because no account is taken of the effects
of font scaling. The way the rectangles are rendered to the printer device context (DC) is that
the lower (or backmost) rectangles are not clipped to those in front of them, leading to a rather
messy result.

Although the state of the printing can hardly be considered satisfactory, I decided to wait to fix
this problem until much later because my guess was that printing the OLE objects would
introduce more complexity in any case, and I wanted to have a clear run at that problem when
the time came.

So What Next?

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                 4/29/2010        7
So now we have an application that, although not wonderful, is at least a platform we can add
some OLE features to. What to do next? As I mentioned earlier, my original plan was to take
this application, replace my own Insert Object dialog box with the one in the OLE development
samples, and go straight to implementing container support. I spent many hours getting the
dialog box to appear, only to discover that I couldn't take the next step.

I needed to call the OleCreate API, which has several parameters. I had most of them from the
result of the Insert Object dialog box but was missing the client site and storage pointers. I had
no idea how to create these two parameters, and NULL wasn't going to do it. So I had to back
up a bit and find out what they were all about. The next article covers adding structured
storage, and subsequent articles go on to add the remaining requirements to implement
container support and much more.

If you still haven't read any of the OLE documents and you're hoping to avoid that by reading
my articles, then I'm afraid you're going to be a bit disappointed. You would do well to at least
read the first few chapters of Kraig Brockschmidt's as-yet-unpublished book, Inside OLE 2, or
the "Architectural Overview of OLE" chapter in the Object Linking and Embedding
Programmer's Reference, Version 2. Without some sort of idea of what OLE is all about, you're
going to find the next step heavy going.

You don't need to understand everything you read. You certainly don't need to remember what
functions go with what interface for what object—all that you need to know for a minimal
implementation will be in the following articles.

784e3b05-145e-461d-beb4-be48a62d4f6d.DOC                4/29/2010        8

To top