Sie sind auf Seite 1von 8

This ad zapped.

Login | My Account

Site Help

Search

Advanced Search | Help


Home > Articles > IT Management > Enterprise Computing > Automation in Delphi COM Programming

Automation in Delphi COM Programming

By Eric Harmon.
Article is provided courtesy of MTP.
Date: Jan 19, 2000.
Save

Discuss

Print

E-mail

Article Information
Contents
1.

Defining Automation

2.

In-Process Automation Servers

3.

Out-of-Process Automation Servers

4.

COM Events and Callbacks

5.

Automating Microsoft ADO

6.

Summary

Article Description
In this selection excerpted from Delphi COM Programming, author Eric Harmon discusses interfaces and
automation, variants and automation, dispinterfaces, dual interfaces, and automating Microsoft ADO.

In the past three chapters, I've spent a lot of time discussing interfaces and how to create COM objects. I
also introduced you to type libraries in Chapter 3, "Type Libraries." This chapter is where everything comes
together. If you've been feeling a little disheartened about COM up until now, this is where that will change.
This chapter is long, but it has many sample programs in it. I personally feel that this is probably the most
important chapter in the book. I want to make sure you have a handle on what's being discussed here. In
this chapter, I'll discuss

Interfaces and automation


Variants and automation

Dispinterfaces

Dual interfaces

Automating Microsoft ADO

In Chapter 3, I showed you what a type library is, how to create one, and how you can read the information
out of a type library. As you saw, extracting the type information manually is tedious at best. The good news
is that you typically won't need to work directly with type library data. In most cases, you will work with a type
library indirectly through automation.

Defining Automation
As its name suggests, automation is a way to automatically control an application from within another
application. Actually, you can build both in-process and out-of-process automation servers. As you'll see later
in this chapter, each type of automation controller has its benefits.
Delphi makes it so easy to create and use automation servers that you almost do not need to know much, if
anything, about COM basics. It's very easy to create a simple automation client.

procedure TForm1.Button1Click(Sender: TObject);


var
V: Variant;
begin
V := CreateOleObject('Word.Basic');
V.AppShow;
V.FileNew;
V.Insert('Automation is easy!');
end;
Believe it or not, this little snippet of code will start Word, create a new document, and insert the text
"Automation is easy!" into the document.
Later in this chapter, in the section titled "Variants," I'll explain exactly what's going on in this code, but my
goal at this point is to show you just how simple automation can be in Delphi.

Interfaces
By now I assume that you understand what interfaces are and how to use them. Interfaces are one of the
two main methods used to gain access to an automation server's COM objects.
When you control an automation server through an interface, you use early binding. Early binding simply
means that all calls made to interface methods are checked for the correct parameters at compile time. As a
Delphi programmer, you should be familiar with early binding.
You've seen numerous examples of interfaces in previous chapters, so I won't show a procedure here for
controlling an automation server through interfaces. This chapter provides many examples that use
interfaces to control an automation server.

Variants

I discussed variants briefly in Chapter 2, "Interfaces and COM," mainly with respect to variant arrays. Not
obviously, variants can also be used to control an automation server.
When you control an automation server through variants, you are using late binding. Late binding means
that method calls are not resolved until runtime. This has some interesting ramifications. Consider the
following code, which connects to Microsoft Word and instructs it to create a new file:

procedure TForm1.Button1Click(Sender: TObject);


var
V: Variant;
begin
V := CreateOleObject('Word.Basic');
V.AppShow;
V.FileNew;
V.Insert('Automation is easy!');
end;
I'm not going to go into detail about the CreateOleObject at this moment. Suffice it to say that it is used to
create an instance of an automation server. I'll come back and discuss that function in more detail later.
What CreateOleObject actually does in this example is start a copy of Microsoft Word. It then obtains a
reference to the Word.Basic interface, and stores that reference in the variant V.
By default, automation servers typically start up as hidden. The AppShow method displays the Word
application.
Then, a call is made to V.FileNew, which creates a new Word document. Delphi (and Windows) performs a
tremendous amount of work behind the scenes to transform V.FileNew into a function call that creates a new
document.
It's interesting to note that a variant is not a pointer to an object. How can you call methods on that "object,"
then? The answer is late binding. Delphi will actually accept anything you type here, without performing any
type checking at all at compile timein other words, Delphi does not perform early binding on variants. For
instance, I could just as easily write the following code:

V.DelphiRules;
Delphi will compile this code just fine, but you can be fairly certain that Word doesn't implement a method
called DelphiRules. If you attempt to execute this statement, you will receive the runtime error shown in
Figure 4.1.
Figure 4.1
Calling a non-existent automation method results in this screen.
To understand how Delphi turns this code into method calls, we need to take a look at the IDispatch
interface.
IDispatch is defined in the file system.pas like this:

IDispatch = interface(IUnknown)

['{00020400-0000-0000-C000-000000000046}']
function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo):
HResult; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID:
Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer):
HResult; stdcall;
end;
The methods GetTypeInfoCount and GetTypeInfo should trigger something in your brain. IDispatch must
consult the type library associated with the automation controller in order to resolve function calls at runtime.
That's exactly correct. As a matter of fact, what happens is the following:
1.
2.

Delphi passes the name of the method to IDispatch.GetIDsOfNames.


GetIDsOfNames returns an integer ID representing the method name.

3.

Delphi calls the Invoke method, using the ID returned in Step 2.

This sequence of steps occurs for every method that you call on an object through a variant. The time
required to execute these three steps is considerably longer than accessing the same object directly through
an interface.
As a Delphi programmer, you might wonder why on earth anyone would want to use IDispatch to access an
automation server. There are two very good reasons for doing so:
1.
2.

You're writing a program or macro in an application that doesn't support interfaces. Examples are
Visual Basic or Microsoft Word.
You're writing a quick and dirty client program in Delphi, and you don't want to go through the
bother of importing a type library.

Dispinterfaces
Somewhere between interfaces and variants are dispinterfaces. A dispinterface declaration looks almost
identical to an interface declaration, except it uses the keyword dispinterface instead of interface. Here is a
simple interface declaration, and then the corresponding dispinterface declaration.

//
*********************************************************************
//
// Interface: IUnitAuto
// Flags:
// GUID:

(4416) Dual OleAutomation Dispatchable


{A1E420C1-F75F-11D2-B3B9-0040F67455FE}

//
*********************************************************************
//
IUnitAuto = interface(IDispatch)
['{A1E420C1-F75F-11D2-B3B9-0040F67455FE}']
function Convert(Quantity: Double; InUnit: Integer; OutUnit:
Integer): Double;
safecall;
end;

//
*********************************************************************
//
// DispIntf: IUnitAutoDisp
// Flags:
// GUID:

(4416) Dual OleAutomation Dispatchable


{A1E420C1-F75F-11D2-B3B9-0040F67455FE}

//
*********************************************************************
//
IUnitAutoDisp = dispinterface
['{A1E420C1-F75F-11D2-B3B9-0040F67455FE}']
function Convert(Quantity: Double; InUnit: Integer; OutUnit:
Integer): Double;
dispid 1;
end;
This Delphi-generated code is taken directly from the first example program later in this chapter, so I'm not
going to explain it in detail right now.
You should notice several things about this code right away.

The IUnitAuto interface is derived from IDispatch, so if you create an automation server that
implements IUnitAuto, clients can use late binding to talk to it.
The IUnitAuto method Convert is declared as safecall.

The IUnitAuto interface and IUnitAutoDisp dispinterface both use the same GUID.

The IUnitAutoDisp dispinterface defines the same method (Convert) that the IUnitAuto interface
defines. However, the dispinterface includes dispid 1 at the end of the method name.

When you use a dispinterface, you eliminate the first two steps associated with IDispatch. The automation
controller does not have to call GetIDsOfNames, and the server does not have to respond with the dispid of
the method in question. Instead, the dispid is determined at compile time. At runtime, the client program
simply calls Invoke with the predetermined dispid.

Dispinterfaces are for client convenience only. You do not actually implement a dispinterface on the server.
The server implements interfaces. The client application can elect to connect to the server using variants or
dispinterfaces, assuming that the server's COM object also supports the IDispatch interface.

Dual Interfaces
A dual interface is simply defined as an automation server that supports clients connecting to it using
interfaces (early bound) as well as clients connecting to it using variants (late bound). Any automation
servers that you create with Delphi will automatically support a dual interface. This is desirable because it
means that any automation server that you write can be accessed by almost any piece of software on the
market today.
This section thoroughly covered automation and the way clients can access automation servers through use
of interfaces, variants, dispinterfaces, and dual interfaces. The next section will take that information and
apply it to the creation and use of in-process automation servers.
2. In-Process Automation Servers | Next Section

Most Active Comments


NewTRON
Posted Jul 9, 2002 11:42 AM by pacoppp
0 Replies
Nice good
Posted Aug 30, 2001 04:15 PM by napoleao
0 Replies
Great
Posted Jan 28, 2004 12:11 PM by Joe
0 Replies

Make a New Comment


You must login in order to post a comment.

This ad zapped.

You May Also Like

1.
o
o

Designing, Building, and Working with COM-Based Components


By Justin Gehtland, Joe Hummel, Ted Pattison, Brian Randell, Doug Turnure
Nov 16, 2001

2.

The Mechanics of COM+

o
o

3.
o
o

By Tim Ewald
Mar 6, 2001
An Overview of COM+
By SCOT HILLIER
Oct 30, 2000
See All Related Articles

Search Related Safari Books

Search electronic versions of over 1500 technical books:

Promotions
New Digital Short Cuts Available Now
Buy One Get One Half Price
Save 30% on Consolidation in the Data Center: Simplifying IT Environments to Reduce Total cost of
Ownership
See All Promotions

Most Popular Articles


Enterprise Data Management in SQL Server 2005
By Eric Brown
Apr 7, 2006
Security in Microsoft IIS
By Martin C. Brown, Don Jones
Nov 13, 2003
Monitoring and Optimizing Apps on Dual-Core and Multiprocessor Systems
By Kurt Hudson
Apr 28, 2006

This ad zapped.
About | Legal Notice | Privacy Policy | Press | Jobs | Write For Us | Contact Us | Advertise | Site Map
2006 Pearson Education, Informit. All rights reserved.
800 East 96th Street, Indianapolis, Indiana 46240

Das könnte Ihnen auch gefallen