Specify the URL by setting the URL property to the location of the server: X.URL := 'http://www.myco.com/MyService.dll/SOAP/IServerInterface'; • If you want to look up the URL, namespac
Trang 1Defining and using SOAP headers
The SOAP encoding of a request to your Web Service application and of the response your application sends include a set of header nodes Some of these, such as the SOAP Action header, are generated and interpreted automatically However, you can also define your own headers to customize the communication between your server and its clients Typically, these headers contain information that is associated with the entire invokable interface, or even with the entire application, rather than just the method that is the subject of a single message
Defining header classes
For each header you want to define, create a descendant of TSOAPHeader
TSOAPHeader is a descendant of TRemotable That is, SOAP header objects are simply
special types of remotable objects As with any remotable object, you can add
published properties to your TSOAPHeader descendant to represent the information
that your header communicates Once you have defined a SOAP header class, it must
be registered with the remotable type registry For more information about remotable objects, see “Using remotable objects” on page 38-6 Note that unlike other remotable classes, which are registered automatically when you register an invokable interface that uses them, you must explicitly write code to register your header types
TSOAPHeader defines two properties that are used to represent attributes of the
SOAP header node These are MustUnderstand and Actor When the MustUnderstand attribute is True, the recipient of a message that includes the header is required to recognize it If the recipient can’t interpret a header with the MustUnderstand
attribute, it must abort the interpretation of the entire message An application can
safely ignore any headers it does not recognize if their MustUnderstand attribute is not set The use of MustUnderstand is qualified by the Actor property Actor is a URI
that identifies the application to which the header is directed Thus, for example, if your Web Service application forwards requests on to another service for further processing, some of the headers in client messages may be targeted at that other
service If such a header includes the MustUnderstand attribute, you should not abort
the request even if your application can’t understand the header Your application is
only concerned with those headers that give its URL as the Actor.
Sending and receiving headers
Once you have defined and registered header classes, they are available for your application to use When your application receives a request, the headers on that
message are automatically converted into the corresponding TSOAPHeader
descendants that you have defined Your application identifies the appropriate header class by matching the name of the header node against the type name you used when you registered the header class Any headers for which it can’t find a
match in the remotable type registry are ignored (or, if their MustUnderstand attribute
is True, the application generates a SOAP fault).
You can access the headers your application receives using the ISOAPHeaders
Trang 2Use the Get method of ISOAPHeaders to access the headers by name For example:
TServiceImpl.GetQuote(Symbol: string): Double;
var
Headers: ISOAPHeaers;
H: TAuthHeader;
begin
Headers := Self as ISOAPHeaders;
Headers.Get(AuthHeader, TSOAPHeader(H)); { Retrieve the authentication header }
try
if H = nil then
raise ERemotableException.Create('SOAP header for authentication required');
{ code here to check name and password }
If you want to include any headers in the response your application generates to a
request message, you can use the same interface ISOAPHeaders defines a Send
method to add headers to the outgoing response Simply create an instance of each header class that corresponds to a header you want to send, set its properties, and
Headers := Self as ISOAPHeaders;
{ code to lookup the quote and set the return value }
{ this code sets the Delay variable to the time delay on the quote }
Handling scalar-type headers
Some Web Services define and use headers that are simple types (such as an integer
or string) rather than a complex structure that corresponds to a remotable type
However, Delphi’s support for SOAP headers requires that you use a TSOAPHeader
descendant to represent header types You can define header classes for simple types
by treating the TSOAPHeader class as a holder class That is, the TSOAPHeader
descendant has a single published property, which is the type of the actual header
To signal that the SOAP representation does not need to include a node for the
TSOAPHeader descendant, call the remotable type registry’s RegisterSerializeOptions
method (after registering the header type) and give your header type an option of
xoSimpleTypeWrapper.
Trang 3Communicating the structure of your headers to other applications
If your application defines headers, you need to allow its clients to access those definitions If those clients are also written in Delphi, you can share the unit that defines and registers your header classes with the client application However, you may want to let other clients know about the headers you use as well To enable your application to export information about its header classes, you must register them with the invocation registry
Like the code that registers your invokable interface, the code to register a header class for export is added to the initialization section of the unit in which it is defined
Use the global InvRegistry function to obtain a reference to the invocation registry and call its RegisterHeaderClass method, indicating the interface with which the
header is associated:
initialization
InvRegistry.RegisterInterface(TypeInfo(IMyWebService)); {register the interface}
InvRegistry.RegisterHeaderClass(TypeInfo(IMyWebService), TMyHeaderClass); {and the header}
end.
You can limit the header to a subset of the methods on the interface by subsequent
calls to the RegisterHeaderMethod method.
Note The implementation section’s uses clause must include the InvokeRegistry unit so
that the call to the InvRegistry function is defined.
Once you have registered your header class with the invocation registry, its
description is added to WSDL documents when you publish your Web Service For information about publishing Web Services, see “Generating WSDL documents for a Web Service application” on page 38-19
Note This registration of your header class with the invocation registry is in addition to the registration of that class with the remotable type registry
Creating custom exception classes for Web Services
When your Web Service application raises an exception in the course of trying to execute a SOAP request, it automatically encodes information about that exception in
a SOAP fault packet, which it returns instead of the results of the method call The client application then raises the exception
By default, the client application raises a generic exception of type
ERemotableExceptionwith the information from the SOAP fault packet You can
transmit additional, application-specific information by deriving an
ERemotableException descendant The values of any published properties you add to
the exception class are included in the SOAP fault packet so that the client can raise
Trang 4If the client also defines and registers your ERemotableException descendant, then
when it receives the SOAP fault packet, it automatically raises an instance of the appropriate exception class, with all properties set to the values in the SOAP fault packet
To allow clients to import information about your ERemotableException descendant,
you must register it with the invocation registry as well as the remotable type
registry Add a call to the RegisterException method of the object that the global
InvRegistry function returns.
Generating WSDL documents for a Web Service application
To allow client applications to know what Web Services your application makes available, you can publish a WSDL document that describes your invokable
interfaces and indicates how to call them
To publish a WSDL document that describes your Web Service, include a
TWSDLHTMLPublish component in your Web Module (The SOAP Server
Application wizard adds this component by default.) TWSDLHTMLPublish is an
auto-dispatching component, which means it automatically responds to incoming messages that request a list of WSDL documents for your Web Service Use the
WebDispatch property to specify the path information of the URL that clients must
use to access the list of WSDL documents The Web browser can then request the list
of WSDL documents by specifying an URL that is made up of the location of the
server application followed by the path in the WebDispatch property This URL looks
something like the following:
http://www.myco.com/MyService.dll/WSDL
Tip If you want to use a physical WSDL file instead, you can display the WSDL
document in your Web browser and then save it to generate a WSDL document file
Note In addition to the WSDL document, the THWSDLHTMLPublish also generates a
WS-Inspection document to describe the service for automated tools The URL for this document looks something like the following:
http://www.myco.com/MyService.dll/inspection.wsil
It is not necessary to publish the WSDL document from the same application that implements your Web Service To create an application that simply publishes the WSDL document, omit the code that implements and registers the implementation objects and only include the code that defines and registers invokable interfaces, remotable classes that represent complex types, and any remotable exceptions
By default, when you publish a WSDL document, it indicates that the services are available at the same URL as the one where you published the WSDL document (but with a different path) If you are deploying multiple versions of your Web Service application, or if you are publishing the WSDL document from a different
application than the one that implements the Web Service, you will need to change the WSDL document so that it includes updated information on where to locate the Web Service
Trang 5To change the URL, use the WSDL administrator The first step is to enable the
administrator You do this by setting the AdminEnabled property of the
TWSDLHTMLPublish component to true Then, when you use your browser to
display the list of WSDL documents, it includes a button to administer them as well Use the WSDL administrator to specify the locations (URLs) where you have
deployed your Web Service application
Writing clients for Web Services
You can write clients that access Web Services that you have written, or any other Web Service that is defined in a WSDL document There are three steps to writing an application that is the client of a Web Service:
• Importing the definitions from a WSDL document
• Obtaining an invokable interface and calling it to invoke the Web Service
• Processing the headers of the SOAP messages that pass between the client and the server
Importing WSDL documents
Before you can use a Web Service, your application must define and register the invokable interfaces and types that are included in the Web Service application To obtain these definitions, you can import a WSDL document (or XML file) that defines the service The WSDL importer creates a unit that defines and registers the
interfaces, headers, and types you need to use For details on using the WSDL importer, see “Using the WSDL importer” on page 38-13
Calling invokable interfaces
To call an invokable interface, your client application must include any definitions of the invokable interfaces and any remotable classes that implement complex types
If the server is written in Delphi, you can use the same units that the server
application uses to define and register these interfaces and classes instead of the files generated by importing a WSDL file Be sure that the unit uses the same namespace URI and SOAPAction header when it registers invokable interfaces These values can
be explicitly specified in the code that registers the interfaces, or it can be
automatically generated If it is automatically generated, the unit that defines the interfaces must have the same name in both client and server, and both client and
server must define the global AppNameSpacePrefix variable to have the same value
Once you have the definition of the invokable interface, there are two ways you can obtain an instance to call:
• If you imported a WSDL document, the importer automatically generates a global
Trang 6Obtaining an invokable interface from the generated function
The WSDL importer automatically generates a function from which you can obtain the invokable interfaces you imported For example, if you imported a WSDL
document that defined an invokable interface named IServerInterface, the generated
unit would include the following global function:
function GetIServerInterface(UseWSDL: Boolean; Addr: string): IServerInterface;
The generated function takes two parameters: UseWSDL and Addr UseWSDL
indicates whether to look up the location of the server from a WSDL document (true),
or whether the client application supplies the URL for the server (false)
When UseWSDL is false, Addr is the URL for the Web Service When UseWSDL is true, Addr is the URL of a WSDL document that describes the Web Service you are
calling If you supply an empty string, this defaults to the document you imported This second approach is best if you expect that the URL for the Web Service may change, or that details such as the namespace or SOAP Action header may change Using this second approach, this information is looked up dynamically at the time your application makes the method call
Note The generated function uses an internal remote interfaced object to implement the invokable interface If you are using this function and find you need to access that
underlying remote interfaced object, you can obtain an IRIOAccess interface from the
invokable interface, and use that to access the remote interfaced object:
Using a remote interfaced object
If you do not use the global function to obtain the invokable interface you want to
call, you can create an instance of THTTPRio for the desired interface:
X := THTTPRio.Create(nil);
Note It is important that you do not explicitly destroy the THTTPRio instance If it is created without an Owner (as in the previous line of code), it automatically frees itself when its interface is released If it is created with an Owner, the Owner is responsible for freeing the THTTPRio instance.
Trang 7Once you have an instance of THTTPRio, provide it with the information it needs to
identify the server interface and locate the server There are two ways to supply this information:
• If you do not expect the URL for the Web Service or the namespaces and soap Action headers it requires to change, you can simply specify the URL for the Web
Service you want to access THTTPRio uses this URL to look up the definition of
the interface, plus any namespace and header information, based on the
information in the invocation registry Specify the URL by setting the URL
property to the location of the server:
X.URL := 'http://www.myco.com/MyService.dll/SOAP/IServerInterface';
• If you want to look up the URL, namespace, or Soap Action header from the
WSDL document dynamically at runtime, you can use the WSDLLocation, Service, and Port properties, and it will extract the necessary information from the WSDL
document:
X.WSDLLocation := 'Cryptography.wsdl';
X.Service := 'Cryptography';
X.Port := 'SoapEncodeDecode';
After specifying how to locate the server and identify the interface, you can obtain an
interface pointer for the invokable interface from the THTTPRio object You obtain this interface pointer using the as operator Simply cast the THTTPRio instance to the
invokable interface:
InterfaceVariable := X as IEncodeDecode;
Code := InterfaceVariable.EncodeValue(5);
When you obtain the interface pointer, THTTPRio creates a vtable for the associated
interface dynamically in memory, enabling you to make interface calls
THTTPRio relies on the invocation registry to obtain information about the invokable
interface If the client application does not have an invocation registry, or if the
invokable interface is not registered, THTTPRio can’t build its in-memory vtable.
Warning If you assign the interface you obtain from THTTPRio to a global variable, you must
change that assignment to nil before shutting down your application For example, if
InterfaceVariable in the previous code sample is a global variable, rather than stack
variable, you must release the interface before the THTTPRio object is freed
Typically, this code goes in the OnDestroy event handler of the form or data module:
procedure TForm1.FormDestroy(Sender: TObject);
begin
InterfaceVariable := nil;
end;
The reason you must reassign a global interface variable to nil is because THTTPRio
builds its vtable dynamically in memory That vtable must still be present when the interface is released If you do not release the interface along with the form or data module, it is released when the global variable is freed on shutdown The memory for global variables may be freed after the form or data module that contains the
THTTPRio object, in which case the vtable will not be available when the interface is
Trang 8Processing headers in client applications
If the Web Service application you are calling expects your client to include any headers in its requests or if its response messages include special headers, your client application needs the definitions of the header classes that correspond to these headers When you import a WSDL document that describes the Web Service application, the importer automatically generates code to declare these header classes and register them with the remotable type registry If the server is written in Delphi, you can use the same units that the server application uses to define and register these header classes instead of the files generated by importing a WSDL file
Be sure that the unit uses the same namespace URI and SOAPAction header when it registers invokable interfaces These values can be explicitly specified in the code that registers the interfaces, or it can be automatically generated If it is automatically generated, the unit that defines the interfaces must have the same name in both client
and server, and both client and server must define the global AppSpacePrefix variable
to have the same value
Note For more information about header classes, see “Defining and using SOAP headers”
on page 38-16
As with a server, client applications use the ISOAPHeaders interface to access
incoming headers and add outgoing headers The remote interfaced object that you
use to call invokable interfaces implements the ISOAPHeaders interface However, you can’t obtain an ISOAPHeaders interface directly from the remote interfaced
object This is because when you try to obtain an interface directly from a remote interfaced object, it generates an in-memory vtable, assuming that the interface is an
invokable interface Thus, you must obtain the ISOAPHeaders interface from the
invokable interface rather than from the remote interfaced object:
(Service as ISOAPHeaders).Send(Hdr); { add the header to outgoing message }
Val := Service.GetQuote('BORL'); { invoke the service }
finally
Hdr.Free;
end;
end;
Trang 10C h a p t e r
39
This chapter describes the socket components that let you create an application that can communicate with other systems using TCP/IP and related protocols Using sockets, you can read and write over connections to other machines without
worrying about the details of the underlying networking software Sockets provide connections based on the TCP/IP protocol, but are sufficiently general to work with related protocols such as User Datagram Protocol (UDP), Xerox Network System (XNS), Digital’s DECnet, or Novell’s IPX/SPX family
Using sockets, you can write network servers or client applications that read from and write to other systems A server or client application is usually dedicated to a single service such as Hypertext Transfer Protocol (HTTP) or File Transfer Protocol (FTP) Using server sockets, an application that provides one of these services can link to client applications that want to use that service Client sockets allow an application that uses one of these services to link to server applications that provide the service
Implementing services
Sockets provide one of the pieces you need to write network servers or client
applications For many services, such as HTTP or FTP, third party servers are readily available Some are even bundled with the operating system, so that there is no need
to write one yourself However, when you want more control over the way the service is implemented, a tighter integration between your application and the network communication, or when no server is available for the particular service you need, then you may want to create your own server or client application For
example, when working with distributed data sets, you may want to write a layer to communicate with databases on other systems
Trang 11Understanding service protocols
Before you can write a network server or client, you must understand the service that your application is providing or using Many services have standard protocols that your network application must support If you are writing a network application for
a standard service such as HTTP, FTP, or even finger or time, you must first
understand the protocols used to communicate with other systems See the
documentation on the particular service you are providing or using
If you are providing a new service for an application that communicates with other systems, the first step is designing the communication protocol for the servers and clients of this service What messages are sent? How are these messages coordinated? How is the information encoded?
Communicating with applications
Often, your network server or client application provides a layer between the networking software and an application that uses the service For example, an HTTP server sits between the Internet and a Web server application that provides content and responds to HTTP request messages
Sockets provide the interface between your network server or client application and the networking software You must provide the interface between your application and the clients that use it You can copy the API of a standard third party server (such
as Apache), or you can design and publish your own API
Services and ports
Most standard services are associated, by convention, with specific port numbers We will discuss port numbers in greater detail later For now, consider the port number a numeric code for the service
If you are implementing a standard service for use in cross-platform applications, Linux socket objects provide methods for you to look up the port number for the service If you are providing a new service, you can specify the associated port
number in the /etc/services file (or its equivalent for your particular Linux
distribution) See your Linux documentation for more information
Trang 12Types of socket connections
Socket connections can be divided into three basic types, which reflect how the connection was initiated and what the local socket is connected to These are
• Client connections
• Listening connections
• Server connections
Once the connection to a client socket is completed, the server connection is
indistinguishable from a client connection Both end points have the same
capabilities and receive the same types of events Only the listening connection is fundamentally different, as it has only a single endpoint
Client connections
Client connections connect a client socket on the local system to a server socket on a remote system Client connections are initiated by the client socket First, the client socket must describe the server socket to which it wishes to connect The client socket then looks up the server socket and, when it locates the server, requests a connection The server socket may not complete the connection right away Server sockets maintain a queue of client requests, and complete connections as they find time When the server socket accepts the client connection, it sends the client socket a full description of the server socket to which it is connecting, and the connection is completed by the client
Listening connections
Server sockets do not locate clients Instead, they form passive “half connections” that listen for client requests Server sockets associate a queue with their listening connections; the queue records client connection requests as they come in When the server socket accepts a client connection request, it forms a new socket to connect to the client, so that the listening connection can remain open to accept other client requests
Server connections
Server connections are formed by server sockets when a listening socket accepts a client request A description of the server socket that completes the connection to the client is sent to the client when the server accepts the connection The connection is established when the client socket receives this description and completes the connection
Trang 13Describing sockets
Sockets let your network application communicate with other systems over the network Each socket can be viewed as an endpoint in a network connection It has an address that specifies:
• The system on which it is running
• The types of interfaces it understands
• The port it is using for the connection
A full description of a socket connection includes the addresses of the sockets on both ends of the connection You can describe the address of each socket endpoint by supplying both the IP address or host and the port number
Before you can make a socket connection, you must fully describe the sockets that form its endpoints Some of the information is available from the system your application is running on For instance, you do not need to describe the local IP address of a client socket—this information is available from the operating system.The information you must provide depends on the type of socket you are working with Client sockets must describe the server they want to connect to Listening server sockets must describe the port that represents the service they provide
Describing the host
The host is the system that is running the application that contains the socket You can describe the host for a socket by giving its IP address, which is a string of four numeric (byte) values in the standard Internet dot notation, such as
123.197.1.2
A single system may support more than one IP address
IP addresses are often difficult to remember and easy to mistype An alternative is to use the host name Host names are aliases for the IP address that you often see in Uniform Resource Locators (URLs) They are strings containing a domain name and service, such as
http://www.ASite.com
Most Intranets provide host names for the IP addresses of systems on the Internet You can learn the host name associated with any IP address (if one already exists) by executing the following command from a command prompt:
nslookup IPADDRESS
where IPADDRESS is the IP address you’re interested in If your local IP address
doesn’t have a host name and you decide you want one, contact your network administrator It is common for computers to refer to themselves with the name
localhost and the IP number 127.0.0.1.
Trang 14Server sockets do not need to specify a host The local IP address can be read from the system If the local system supports more than one IP address, server sockets will listen for client requests on all IP addresses simultaneously When a server socket accepts a connection, the client socket provides the remote IP address.
Client sockets must specify the remote host by providing either its host name or IP address
Choosing between a host name and an IP address
Most applications use the host name to specify a system Host names are easier to remember, and easier to check for typographical errors Further, servers can change the system or IP address that is associated with a particular host name Using a host name allows the client socket to find the abstract site represented by the host name, even when it has moved to a new IP address
If the host name is unknown, the client socket must specify the server system using its IP address Specifying the server system by giving the IP address is faster When you provide the host name, the socket must search for the IP address associated with the host name, before it can locate the server system
Using ports
While the IP address provides enough information to find the system on the other end of a socket connection, you also need a port number on that system Without port numbers, a system could only form a single connection at a time Port numbers are unique identifiers that enable a single system to host multiple connections
simultaneously, by giving each connection a separate port number
Earlier, we described port numbers as numeric codes for the services implemented
by network applications This is actually just a convention that allows listening server connections to make themselves available on a fixed port number so that they can be found by client sockets Server sockets listen on the port number associated with the service they provide When they accept a connection to a client socket, they create a separate socket connection that uses a different, arbitrary, port number This way, the listening connection can continue to listen on the port number associated with the service
Client sockets use an arbitrary local port number, as there is no need for them to be found by other sockets They specify the port number of the server socket to which they want to connect so that they can find the server application Often, this port number is specified indirectly, by naming the desired service
Trang 15Using socket components
The Internet palette page includes three socket components that allow your network application to form connections to other machines, and that allow you to read and write information over that connection These are:
to be concerned with the details of establishing the connection or managing the socket messages
If you want to customize the details of the connections that the socket components make on your behalf, you can use the properties, events, and methods of the socket objects
Getting information about the connection
After completing the connection to a client or server socket, you can use the client or server socket object associated with your socket component to obtain information
about the connection Use the LocalHost and LocalPort properties to determine the
address and port number used by the local client or server socket, or use the
RemoteHost and RemotePort properties to determine the address and port number
used by the remote client or server socket Use the GetSocketAddr method to build a
valid socket address based on the host name and port number You can use the
LookupPort method to look up the port number Use the LookupProtocol method to
look up the protocol number Use the LookupHostName method to look up the host
name based on the host machine’s IP address
To view network traffic in and out of the socket, use the BytesSent and BytesReceived
properties
Using client sockets
Add a TcpClient or UdpSocket component to your form or data module to turn your
application into a TCP/IP or UDP client Client sockets allow you to specify the server socket you want to connect to, and the service you want that server to provide Once you have described the desired connection, you can use the client socket component to complete the connection to the server
Each client socket component uses a single client socket object to represent the client endpoint in a connection
Trang 16Specifying the desired server
Client socket components have a number of properties that allow you to specify the
server system and port to which you want to connect Use the RemoteHost property to
specify the remote host server by either its host name or IP address
In addition to the server system, you must specify the port on the server system that
your client socket will connect to You can use the RemotePort property to specify the
server port number directly or indirectly by naming the target service
Forming the connection
Once you have set the properties of your client socket component to describe the server you want to connect to, you can form the connection at runtime by calling the
Open method If you want your application to form the connection automatically
when it starts up, set the Active property to True at design time, using the Object
Inspector
Getting information about the connection
After completing the connection to a server socket, you can use the client socket object associated with your client socket component to obtain information about the
connection Use the LocalHost and LocalPort properties to determine the address and
port number used by the client and server sockets to form the end points of the
connection You can use the Handle property to obtain a handle to the socket
connection to use when making socket calls
Closing the connection
When you have finished communicating with a server application over the socket
connection, you can shut down the connection by calling the Close method The
connection may also be closed from the server end If that is the case, you will receive
notification in an OnDisconnect event.
Using server sockets
Add a server socket component (TcpServer or UdpSocket) to your form or data module
to turn your application into an IP server Server sockets allow you to specify the service you are providing or the port you want to use to listen for client requests You can use the server socket component to listen for and accept client connection requests
Each server socket component uses a single server socket object to represent the server endpoint in a listening connection It also uses a server client socket object for the server endpoint of each active connection to a client socket that the server accepts
Trang 17Specifying the port
Before your server socket can listen to client requests, you must specify the port that
your server will listen on You can specify this port using the LocalPort property If
your server application is providing a standard service that is associated by
convention with a specific port number, you can also specify the service name using
the LocalPort property It is a good idea to use the service name instead of a port
number, because it is easy to introduce typographical errors when specifying the port number
Listening for client requests
Once you have set the port number of your server socket component, you can form a
listening connection at runtime by calling the Open method If you want your
application to form the listening connection automatically when it starts up, set the
Active property to True at design time, using the Object Inspector.
Connecting to clients
A listening server socket component automatically accepts client connection requests when they are received You receive notification every time this occurs in an
OnAccept event.
Closing server connections
When you want to shut down the listening connection, call the Close method or set the Active property to False This shuts down all open connections to client
applications, cancels any pending connections that have not been accepted, and then shuts down the listening connection so that your server socket component does not accept any new connections
When TCP clients shut down their individual connections to your server socket, you
are informed by an OnDisconnect event.
Responding to socket events
When writing applications that use sockets, you can write or read to the socket
anywhere in the program You can write to the socket using the SendBuf, SendStream,
or Sendln methods in your program after the socket has been opened You can read from the socket using the similarly-named methods ReceiveBuf and Receiveln The
OnSend and OnReceive events are triggered every time something is written or read
from the socket They can be used for filtering Every time you read or write, a read
or write event is triggered
Both client sockets and server sockets generate error events when they receive error messages from the connection
Socket components also receive two events in the course of opening and completing
a connection If your application needs to influence how the opening of the socket
Trang 18Error events
Client and server sockets generate OnError events when they receive error messages from the connection You can write an OnError event handler to respond to these
error messages The event handler is passed information about
• What socket object received the error notification
• What the socket was trying to do when the error occurred
• The error code that was provided by the error message
You can respond to the error in the event handler, and change the error code to 0 to prevent the socket from raising an exception
Client events
When a client socket opens a connection, the following events occur:
• The socket is set up and initialized for event notification
• An OnCreateHandle event occurs after the server and server socket is created At this point, the socket object available through the Handle property can provide
information about the server or client socket that will form the other end of the connection This is the first chance to obtain the actual port used for the
connection, which may differ from the port of the listening sockets that accepted the connection
• The connection request is accepted by the server and completed by the client socket
• When the connection is established, the OnConnect notification event occurs.
Server events
Server socket components form two types of connections: listening connections and connections to client applications The server socket receives events during the formation of each of these connections
Events when listening
Just before the listening connection is formed, the OnListening event occurs You can use its Handle property to make changes to the socket before it is opened for listing
For example, if you want to restrict the IP addresses the server uses for listening, you
would do that in an OnListening event handler.
Trang 19Events with client connections
When a server socket accepts a client connection request, the following events occur:
• An OnAccept event occurs, passing in the new TTcpClient object to the event handler This is the first point when you can use the properties of TTcpClient to
obtain information about the server endpoint of the connection to a client
• If BlockMode is bmThreadBlocking an OnGetThread event occurs If you want to provide your own customized descendant of TServerSocketThread, you can create one in an OnGetThread event handler, and that will be used instead of
TServerSocketThread If you want to perform any initialization of the thread, or
make any socket API calls before the thread starts reading or writing over the
connection, you should use the OnGetThread event handler for these tasks as well
• The client completes the connection and an OnAccept event occurs With a
non-blocking server, you may want to start reading or writing over the socket
connection at this point
Reading and writing over socket connections
The reason you form socket connections to other machines is so that you can read or write information over those connections What information you read or write, or when you read it or write it, depends on the service associated with the socket connection
Reading and writing over sockets can occur asynchronously, so that it does not block the execution of other code in your network application This is called a non-blocking connection You can also form blocking connections, where your application waits for the reading or writing to be completed before executing the next line of code
Trang 20Reading and writing events
Non-blocking sockets generate reading and writing events when they need to read or
write over the connection You can respond to these notifications in an OnReceive or
OnSend event handler
The socket object associated with the socket connection is provided as a parameter to the read or write event handlers This socket object provides a number of methods to allow you to read or write over the connection
To read from the socket connection, use the ReceiveBuf or Receiveln method To write
to the socket connection, use the SendBuf, SendStream, or Sendln method.
Blocking connections
When the connection is blocking, your socket must initiate reading or writing over the connection It cannot wait passively for a notification from the socket connection Use a blocking socket when your end of the connection is in charge of when reading and writing takes place
For client or server sockets, set the BlockMode property to bmBlocking to form a
blocking connection Depending on what else your client application does, you may want to create a new execution thread for reading or writing, so that your application can continue executing code on other threads while it waits for the reading or writing over the connection to be completed
For server sockets, set the BlockMode property to bmBlocking or bmThreadBlocking to
form a blocking connection Because blocking connections hold up the execution of all other code while the socket waits for information to be written or read over the connection, server socket components always spawn a new execution thread for
every client connection when the BlockMode is bmThreadBlocking When the BlockMode
is bmBlocking, program execution is blocked until a new connection is established.
Trang 22P a r t
IV
The chapters in “Developing COM-based applications” present concepts necessary for building COM-based applications, including Automation controllers,
Automation servers, ActiveX controls, and COM+ applications
Trang 24C h a p t e r
40
Delphi provides wizards and classes to make it easy to implement applications based
on the Component Object Model (COM) from Microsoft With these wizards, you can create COM-based classes and components to use within applications or you can create fully functional COM clients or servers that implement COM objects,
Automation servers (including Active Server Objects), ActiveX controls, or
ActiveForms
Note COM components such as those on the ActiveX, COM+, and Servers tabs of the Component palette are not available for use in CLX applications This technology is for use on Windows only and is not cross-platform
COM is a language-independent software component model that enables interaction between software components and applications running on a Windows platform The key aspect of COM is that it enables communication between components, between applications, and between clients and servers through clearly defined interfaces Interfaces provide a way for clients to ask a COM component which features it supports at runtime To provide additional features for your component, you simply add an additional interface for those features
Applications can access the interfaces of COM components that exist on the same computer as the application or that exist on another computer on the network using a mechanism called Distributed COM (DCOM) For more information on clients, servers, and interfaces see, “Parts of a COM application,” on page 40-3
This chapter provides a conceptual overview of the underlying technology on which Automation and ActiveX controls are built Later chapters provide details on creating Automation objects and ActiveX controls in Delphi
Trang 25COM as a specification and implementation
COM is both a specification and an implementation The COM specification defines how objects are created and how they communicate with each other According to this specification, COM objects can be written in different languages, run in different process spaces and on different platforms As long as the objects adhere to the written specification, they can communicate This allows you to integrate legacy code
as a component with new components implemented in object-oriented languages The COM implementation is built into the Win32 subsystem, which provides a number of core services that support the written specification The COM library contains a set of standard interfaces that define the core functionality of a COM object, and a small set of API functions designed for the purpose of creating and managing COM objects
When you use Delphi wizards and VCL objects in your application, you are using Delphi’s implementation of the COM specification In addition, Delphi provides some wrappers for COM services for those features that it does not implement directly (such as Active Documents) You can find these wrappers defined in the ComObj unit and the API definitions in the AxCtrls unit
Note Delphi’s interfaces and language follow the COM specification Delphi implements objects conforming to the COM spec using a set of classes called the Delphi ActiveX framework (DAX) These classes are found in the AxCtrls, OleCtrls, and OleServer units In addition, the Delphi interface to the COM API is in ActiveX.pas and
ComSvcs.pas
COM extensions
As COM has evolved, it has been extended beyond the basic COM services COM serves as the basis for other technologies such as Automation, ActiveX controls, Active Documents, and Active Directories For details on COM extensions, see
“COM extensions” on page 40-10
In addition, when working in a large, distributed environment, you can create transactional COM objects Prior to Windows 2000, these objects were not
architecturally part of COM, but rather ran in the Microsoft Transaction Server (MTS) environment With the advent of Windows 2000, this support is integrated into COM+ Transactional objects are described in detail in Chapter 46, “Creating MTS or COM+ objects.”
Delphi provides wizards to easily implement applications that incorporate the above technologies in the Delphi environment For details, see “Implementing COM objects with wizards” on page 40-19
Trang 26Parts of a COM application
When implementing a COM application, you supply the following:
COM interfaces
COM clients communicate with objects through COM interfaces Interfaces are groups of logically or semantically related routines which provide communication between a provider of a service (server object) and its clients The standard way to depict a COM interface is shown in Figure 40.1:
Figure 40.1 A COM interface
For example, every COM object must implement the basic interface, IUnknown Through a routine called QueryInterface in IUnknown, clients can request other
interfaces implemented by the server
Objects can have multiple interfaces, where each interface implements a feature An interface provides a way to convey to the client what service it provides, without providing implementation details of how or where the object provides this service
COM interface The way in which an object exposes its services externally to clients
A COM object provides an interface for each set of related methods and properties Note that COM properties are not identical to properties on VCL objects COM properties always use read and write access methods
COM server A module, either an EXE, DLL, or OCX, that contains the code for a
COM object Object implementations reside in servers A COM object implements one or more interfaces
COM client The code that calls the interfaces to get the requested services from
the server Clients know what they want to get from the server (through the interface); clients do not know the internals of how the server provides the services Delphi eases the process in creating a client by letting you install COM servers (such as a Word document
or PowerPoint slide) as components on the Component Palette This allows you to connect to the server and hook its events through the Object Inspector
COM Object Interface
Trang 27Key aspects of COM interfaces are as follows:
• Once published, interfaces are immutable; that is, they do not change You can rely
on an interface to provide a specific set of functions Additional functionality is provided by additional interfaces
• By convention, COM interface identifiers begin with a capital I and a symbolic
name that defines the interface, such as IMalloc or IPersist
• Interfaces are guaranteed to have a unique identification, called a Globally
Unique Identifier (GUID), which is a 128-bit randomly generated number
Interface GUIDs are called Interface Identifiers (IIDs) This eliminates naming
conflicts between different versions of a product or different products
• Interfaces are language independent You can use any language to implement a COM interface as long as the language supports a structure of pointers, and can call a function through a pointer either explicitly or implicitly
• Interfaces are not objects themselves; they provide a way to access an object Therefore, clients do not access data directly; clients access data through an interface pointer Windows 2000 adds an additional layer of indirection known as
an interceptor through which it provides COM+ features such as just-in-time activation and object pooling
• Interfaces are always inherited from the fundamental interface, IUnknown.
• Interfaces can be redirected by COM through proxies to enable interface method calls to call between threads, processes, and networked machines, all without the client or server objects ever being aware of the redirection For more information see , “In-process, out-of-process, and remote servers,” on page 40-7
The fundamental COM interface, IUnknown
All COM objects must support the fundamental interface, called IUnknown, a typedef
to the base interface type IInterface IUnknown contains the following routines:
Clients obtain pointers to other interfaces through the IUnknown method,
QueryInterface QueryInterface knows about every interface in the server object and
can give a client a pointer to the requested interface When receiving a pointer to an interface, the client is assured that it can call any method of the interface
Objects track their own lifetime through the IUnknown methods, AddRef and Release,
which are simple reference counting methods As long as an object’s reference count
is nonzero, the object remains in memory Once the reference count reaches zero, the interface implementation can safely dispose of the underlying object(s)
QueryInterface Provides pointers to other interfaces that the object supports.AddRef and Release Simple reference counting methods that keep track of the
object’s lifetime so that an object can delete itself when the client no longer needs its service
Trang 28COM interface pointers
An interface pointer is a pointer to an object instance that points, in turn, to the implementation of each method in the interface The implementation is accessed
through an array of pointers to these methods, which is called a vtable Vtables are
similar to the mechanism used to support virtual functions in Delphi Because of this similarity, the compiler can resolve calls to methods on the interface the same way it resolves calls to methods on Delphi classes
The vtable is shared among all instances of an object class, so for each object instance, the object code allocates a second structure that contains its private data The client’s
interface pointer, then, is a pointer to the pointer to the vtable, as shown in the
following diagram
Figure 40.2 Interface vtable
In Windows 2000 and subsequent versions of Windows, when an object is running under COM+, an added level of indirection is provided between the interface pointer and the vtable pointer The interface pointer available to the client points at an interceptor, which in turn points at the vtable This allows COM+ to provide such services as just-in-time activation, whereby the server can be deactivated and reactivated dynamically in a way that is opaque to the client To achieve this, COM+ guarantees that the interceptor behaves as if it were an ordinary vtable pointer
COM servers
A COM server is an application or a library that provides services to a client
application or library A COM server consists of one or more COM objects, where a COM object is a set of properties and methods
Clients do not know how a COM object performs its service; the object’s
implementation remains encapsulated An object makes its services available
through its interfaces as described previously.
In addition, clients do not need to know where a COM object resides COM provides
transparent access regardless of the object’s location
Pointer to Function 1
Implementation
of interface functions
vtable pointer interface pointer
object
Pointer to Function 2 Pointer to Function 3
Trang 29When a client requests a service from a COM object, the client passes a class identifier (CLSID) to COM A CLSID is simply a GUID that identifies a COM object COM uses this CLSID, which is registered in the system registry, to locate the appropriate server implementation Once the server is located, COM brings the code into memory, and has the server instantiate an object instance for the client This process is handled indirectly, through a special object called a class factory (based on interfaces) that creates instances of objects on demand
As a minimum, a COM server must perform the following:
• Register entries in the system registry that associate the server module with the class identifier (CLSID)
• Implement a class factory object, which manufactures another object of a
particular CLSID
• Expose the class factory to COM
• Provide an unloading mechanism through which a server that is not servicing clients can be removed from memory
Note Delphi wizards automate the creation of COM objects and servers as described in
“Implementing COM objects with wizards” on page 40-19
CoClasses and class factories
A COM object is an instance of a CoClass, which is a class that implements one or
more COM interfaces The COM object provides the services as defined by its interfaces
CoClasses are instantiated by a special type of object called a class factory Whenever
an object’s services are requested by a client, a class factory creates an object instance for that particular client Typically, if another client requests the object’s services, the class factory creates another object instance to service the second client (Clients can also bind to running COM objects that register themselves to support it.)
A CoClass must have a class factory and a class identifier (CLSID) so that it can be instantiated externally, that is, from another module Using these unique identifiers for CoClasses means that they can be updated whenever new interfaces are
implemented in their class A new interface can modify or add methods without affecting older versions, which is a common problem when using DLLs
Delphi wizards take care of assigning class identifiers and of implementing and instantiating class factories
Trang 30In-process, out-of-process, and remote servers
With COM, a client does not need to know where an object resides, it simply makes a call to an object’s interface COM performs the necessary steps to make the call These steps differ depending on whether the object resides in the same process as the client,
in a different process on the client machine, or in a different machine across the network The different types of servers are known as:
As shown in Figure 40.3, for in-process servers, pointers to the object interfaces are in the same process space as the client, so COM makes direct calls into the object implementation
Figure 40.3 In-process server
Note This is not always true under COM+ When a client makes a call to an object in a different context, COM+ intercepts the call so that it behaves like a call to an out-of-process server (see below), even if the server is in-process See Chapter 46, “Creating MTS or COM+ objects” for more information working with COM+
In-process server A library (DLL) running in the same process space as the client,
for example, an ActiveX control embedded in a Web page viewed under Internet Explorer or Netscape Here, the ActiveX control is downloaded to the client machine and invoked within the same process as the Web browser.The client communicates with the in-process server using direct calls to the COM interface
Out-of-process server
(or local server)
Another application (EXE) running in a different process space but on the same machine as the client For example, an Excel
spreadsheet embedded in a Word document are two separate applications running on the same machine
The local server uses COM to communicate with the client Remote server A DLL or another application running on a different machine
from that of the client For example, a Delphi database application is connected to an application server on another machine in the network
The remote server uses distributed COM (DCOM) to access interfaces and communicate with the application server
Client Process
Client
Server In-process Object
Trang 31As shown in Figure 40.4, when the process is either in a different process or in a different machine altogether, COM uses a proxy to initiate remote procedure calls
The proxy resides in the same process as the client, so from the client’s perspective,
all interface calls look alike The proxy intercepts the client’s call and forwards it to where the real object is running The mechanism that enables the client to access objects in a different process space, or even different machine, as if they were in their
own process, is called marshaling
Figure 40.4 Out-of-process and remote servers
The difference between out-of-process and remote servers is the type of interprocess communication used The proxy uses COM to communicate with an out-of-process server, it uses distributed COM (DCOM) to communicate with a remote machine DCOM transparently transfers a local object request to the remote object running on
a different machine
Note For remote procedure calls, DCOM uses the RPC protocol provided by Open Group’s Distributed Computing Environment (DCE) For distributed security, DCOM uses the NT LAN Manager (NTLM) security protocol For directory services, DCOM uses the Domain Name System (DNS)
The marshaling mechanism
Marshaling is the mechanism that allows a client to make interface function calls to remote objects in another process or on a different machine Marshaling
• Takes an interface pointer in the server’s process and makes a proxy pointer available to code in the client process
• Transfers the arguments of an interface call as passed from the client and places the arguments into the remote object’s process space
DCOM RPC
Client Process
Client
In-process Proxy
Out-of-Process Server
Object
Remote machine Remote machine
DCOM
Stub
Remote server
In-process Object COM
RPC
Trang 32For any interface call, the client pushes arguments onto a stack and makes a function call through the interface pointer If the call to the object is not in-process, the call gets passed to the proxy The proxy packs the arguments into a marshaling packet and transmits the structure to the remote object The object’s stub unpacks the packet, pushes the arguments onto the stack, and calls the object’s implementation In essence, the object recreates the client’s call in its own address space.
The type of marshaling that occurs depends on what interface the COM object implements Objects can use a standard marshaling mechanism provided by the
IDispatch interface This is a generic marshaling mechanism that enables
communication through a system-standard remote procedure call (RPC) For details
on the IDispatch interface, see “Automation interfaces” on page 43-13 Even if the object does not implement IDispatch, if it limits itself to automation-compatible types
and has a registered type library, COM automatically provides marshaling support.Applications that do not limit themselves to automation-compatible types or register
a type library must provide their own marshaling Marshaling is provided either
through an implementation of the IMarshal interface, or by using a separately
generated proxy/stub DLL Delphi does not support the automatic generation of proxy/stub DLLs
Aggregation
Sometimes, a server object makes use of another COM object to perform some of its functions For example, an inventory management object might make use of a separate invoicing object to handle customer invoices If the inventory management object wants to present the invoice interface to clients, however, there is a problem:
Although a client that has the inventory interface can call QueryInterface to obtain the
invoice interface, when the invoice object was created it did not know about the inventory management object and can’t return an inventory interface in response to a
call to QueryInterface A client that has the invoice interface can’t get back to the
inventory interface
To avoid this problem, some COM objects support aggregation When the inventory
management object creates an instance of the invoice object, it passes it a copy of its
own IUnknown interface The invoice object can then use that IUnknown interface to handle any QueryInterface calls that request an interface, such as the inventory
interface, that it does not support When this happens, the two objects together are called an aggregate The invoice object is called the inner, or contained object of the aggregate, and the inventory object is called the outer object
Note In order to act as the outer object of an aggregate, a COM object must create the inner
object using the Windows API CoCreateInstance or CoCreateInstanceEx, passing its
IUnknown pointer as a parameter that the inner object can use for QueryInterface calls
In order to create an object that can act as the inner object of an aggregate, it must
descend from TContainedObject When the object is created, the IUnknown interface of
the outer object is passed to the constructor so that it can be used by the
QueryInterface method on calls that the inner object can’t handle.
Trang 33COM clients
Clients can always query the interfaces of a COM object to determine what it is capable of providing All COM objects allow clients to request known interfaces In
addition, if the server supports the IDispatch interface, clients can query the server for
information about what methods the interface supports Server objects have no expectations about the client using its objects Similarly, clients don’t need to know how (or even where) an object provides the services; they simply rely on server objects to provide the services they advertise through their interfaces
There are two types of COM clients, controllers and containers Controllers launch the server and interact with it through its interface They request services from the COM object or drive it as a separate process Containers host visual controls or objects that appear in the container’s user interface They use predefined interfaces to negotiate display issues with server objects It is impossible to have a container relationship over DCOM; for example, visual controls that appear in the container's user interface must be located locally This is because the controls are expected to paint themselves, which requires that they have access to local GDI resources.Delphi makes it easier for you to develop COM clients by letting you import a type library or ActiveX control into a component wrapper so that server objects look like other VCL components For details on this process, see Chapter 42, “Creating COM clients.”
COM extensions
COM was originally designed to provide core communication functionality and to enable the broadening of this functionality through extensions COM itself has extended its core functionality by defining specialized sets of interfaces for specific purposes
The following lists some of the services COM extensions currently provide
Subsequent sections describe these services in greater detail
Automation servers Automation refers to the ability of an application to control
the objects in another application programmatically
Automation servers are the objects that can be controlled by other executables at runtime
ActiveX controls ActiveX controls are specialized in-process servers, typically
intended for embedding in a client application The controls offer both design and runtime behaviors as well as events
Active Server Pages Active Server Pages are scripts that generate HTML pages
The scripting language includes constructs for creating and running Automation objects That is, the Active Server Page acts as an Automation controller
Trang 34The following diagram illustrates the relationship of the COM extensions and how they are built upon COM:
Figure 40.5 COM-based technologies
Active Documents Objects that support linking and embedding, drag-and-drop,
visual editing, and in-place activation Word documents and Excel spreadsheets are examples of Active Documents
Transactional objects Objects that include additional support for responding to
large numbers of clients This includes features such as in-time activation, transactions, resource pooling, and security services These features were originally handled by MTS but have been built into COM with the advent of COM+
just-Type libraries A collection of static data structures, often saved as a
resource, that provides detailed type information about an object and its interfaces Clients of Automation servers, ActiveX controls, and transactional objects expect type information to be available
Trang 35COM objects can be visual or non-visual Some must run in the same process space as their clients; others can run in different processes or remote machines, as long as the objects provide marshaling support Table 40.1 summarizes the types of COM objects that you can create, whether they are visual, process spaces they can run in, how they provide marshaling, and whether they require a type library
Automation servers
Automation refers to the ability of an application to control the objects in another application programmatically, like a macro that can manipulate more than one application at the same time The server object being manipulated is called the Automation object, and the client of the Automation object is referred to as an Automation controller
Automation can be used on in-process, local, and remote servers
Automation is characterized by two key points:
• The Automation object defines a set of properties and commands, and describes their capabilities through type descriptions In order to do this, it must have a way
to provide information about its interfaces, the interface methods, and those methods’ arguments Typically, this information is available in a type library The Automation server can also generate type information dynamically when queried
via its IDispatch interface (see following).
• Automation objects make their methods accessible so that other applications can
use them For this, they implement the IDispatch interface Through this interface
an object can expose all of its methods and properties Through the primary method of this interface, the object’s methods can be invoked, once having been identified through type information
Table 40.1 COM object requirements
Object
Visual Object? Process space Communication Type library
Active Document Usually In-process, or
Automatically marshaled using
the IDispatch interface (for out-of
process and remote servers)
Required for automatic marshaling ActiveX Control Usually In-process Automatically marshaled using
the IDispatch interface
Required MTS or COM+ Occasionally In-process for MTS,
any for COM+
Automatically marshaled via a type library
Required In-process custom
interface object
Optionally In-process No marshaling required for
in-process servers
Recommended Other custom
interface object
Optionally In-process,
out-of-process, or remote
Automatically marshaled via a type library; otherwise, manually marshaled using custom interfaces
Recommended
Trang 36Developers often use Automation to create and use non-visual OLE objects that run
in any process space because the Automation IDispatch interface automates the
marshaling process Automation does, however, restrict the types that you can use For a list of types that are valid for type libraries in general, and Automation
interfaces in particular, see “Valid types” on page 41-12
For information on writing an Automation server, see Chapter 43, “Creating simple COM servers.”
Active Server Pages
The Active Server Page (ASP) technology lets you write simple scripts, called Active Server Pages, that can be launched by clients via a Web server Unlike ActiveX controls, which run on the client, Active Server Pages run on the server, and return a resulting HTML page to clients
Active Server Pages are written in Jscript or VB script The script runs every time the server loads the Web page That script can then launch an embedded Automation server (or Enterprise Java Bean) For example, you can write an Automation server, such as one to create a bitmap or connect to a database, and this server accesses data that gets updated every time a client loads the Web page
Active Server Pages rely on the Microsoft Internet Information Server (IIS)
environment to serve your Web pages
Delphi wizards let you create an Active Server Object, which is an Automation object specifically designed to work with an Active Server Page For more information about creating and using these types of objects, see Chapter 44, “Creating an Active Server Page.”
ActiveX controls
ActiveX is a technology that allows COM components, especially controls, to be more compact and efficient This is especially necessary for controls that are intended for Intranet applications that need to be downloaded by a client before they are used ActiveX controls are visual controls that run only as in-process servers, and can be plugged into an ActiveX control container application They are not complete applications in themselves, but can be thought of as prefabricated OLE controls that are reusable in various applications ActiveX controls have a visible user interface, and rely on predefined interfaces to negotiate I/O and display issues with their host containers
ActiveX controls make use of Automation to expose their properties, methods, and events Features of ActiveX controls include the ability to fire events, bind to data sources, and support licensing
Trang 37One use of ActiveX controls is on a Web site as interactive objects in a Web page As such, ActiveX is a standard that targets interactive content for the World Wide Web, including the use of ActiveX Documents used for viewing non-HTML documents through a Web browser For more information about ActiveX technology, see the Microsoft ActiveX Web site.
Delphi wizards allow you to easily create ActiveX controls For more information about creating and using these types of objects, see Chapter 45, “Creating an ActiveX control.”
Active Documents
Active Documents (previously referred to as OLE documents) are a set of COM services that support linking and embedding, drag-and-drop, and visual editing Active Documents can seamlessly incorporate data or objects of different formats, such as sound clips, spreadsheets, text, and bitmaps
Unlike ActiveX controls, Active Documents are not limited to in-process servers; they can be used in cross-process applications
Unlike Automation objects, which are almost never visual, Active Document objects can be visually active in another application Thus, Active Document objects are associated with two types of data: presentation data, used for visually displaying the object on a display or output device, and native data, used to edit an object
Active Document objects can be document containers or document servers While Delphi does not provide an automatic wizard for creating Active Documents, you
can use the VCL class, TOleContainer, to support linking and embedding of existing
Active Documents
You can also use TOleContainer as a basis for an Active Document container To
create objects for Active Document servers, use the COM object wizard and add the appropriate interfaces, depending on the services the object needs to support For more information about creating and using Active Document servers, see the Microsoft ActiveX Web site
Note While the specification for Active Documents has built-in support for marshaling in cross-process applications, Active Documents do not run on remote servers because they use types that are specific to a system on a given machine such as window handles, menu handles, and so on
Trang 38Transactional objects
Delphi uses the term “transactional objects” to refer to objects that take advantage of the transaction services, security, and resource management supplied by Microsoft Transaction Server (MTS) (for versions of Windows prior to Windows 2000) or COM+ (for Windows 2000 and later) These objects are designed to work in a large, distributed environment
The transaction services provide robustness so that activities are always completed
or rolled back (the server never partially completes an activity) The security services allow you to expose different levels of support to different classes of clients The resource management allows an object to handle more clients by pooling resources or keeping objects active only when they are in use To enable the system to provide
these services, the object must implement the IObjectControl interface To access the services, transactional objects use an interface called IObjectContext, which is created
on their behalf by MTS or COM+
Under MTS, the server object must be built into a library (DLL), which is then installed in the MTS runtime environment That is, the server object is an in-process server that runs in the MTS runtime process space Under COM+, this restriction does not apply because all COM calls are routed through an interceptor To clients, the difference between MTS and COM+ is transparent
MTS or COM+ servers group transactional objects that run in the same process space Under MTS, this group is called an MTS package, while under COM+ it is called a COM+ application A single machine can be running several different MTS packages (or COM+ applications), where each one is running in a separate process space
To clients, the transactional object may appear like any other COM server object The client need never know about transactions, security, or just-in-time activation unless
it is initiating a transaction itself
Both MTS and COM+ provide a separate tool for administering transactional objects This tool lets you configure objects into packages or COM+ applications, view the packages or COM+ applications installed on a computer, view or change the
attributes of the included objects, monitor and manage transactions, make objects available to clients, and so on Under MTS, this tool is the MTS Explorer Under COM+ it is the COM+ Component Manager
Trang 39Type libraries
Type libraries provide a way to get more type information about an object than can
be determined from an object’s interface The type information contained in type libraries provides needed information about objects and their interfaces, such as what interfaces exist on what objects (given the CLSID), what member functions exist
on each interface, and what arguments those functions require
You can obtain type information either by querying a running instance of an object or
by loading and reading type libraries With this information, you can implement a client which uses a desired object, knowing specifically what member functions you need, and what to pass those member functions
Clients of Automation servers, ActiveX controls, and transactional objects expect type information to be available All of Delphi’s wizards generate a type library automatically, although the COM object wizard makes this optional You can view or
edit this type information by using the Type Library Editor as described in
Chapter 41, “Working with type libraries.”
This section describes what a type library contains, how it is created, when it is used, and how it is accessed For developers wanting to share interfaces across languages, the section ends with suggestions on using type library tools
The content of type libraries
Type libraries contain type information, which indicates which interfaces exist in
which COM objects, and the types and numbers of arguments to the interface methods These descriptions include the unique identifiers for the CoClasses
(CLSIDs) and the interfaces (IIDs), so that they can be properly accessed, as well as the dispatch identifiers (dispIDs) for Automation interface methods and properties Type libraries can also contain the following information:
• Descriptions of custom type information associated with custom interfaces
• Routines that are exported by the Automation or ActiveX server, but that are not interface methods
• Information about enumeration, record (structures), unions, alias, and module data types
• References to type descriptions from other type libraries
Trang 40Creating type libraries
With traditional development tools, you create type libraries by writing scripts in the Interface Definition Language (IDL) or the Object Description Language (ODL), then running that script through a compiler However, Delphi automatically generates a type library when you create a COM object (including ActiveX controls, Automation objects, remote data modules, and so on) using any of the wizards on the ActiveX or Multitier page of the new items dialog (You can opt not to create a type library when using the COM object wizard.) You can also create a type library by choosing from the main menu, File|New|Other, select the ActiveX tab, and choose Type Library You can view the type library using Delphi’s Type Library editor You can easily edit your type library using the Type Library editor and Delphi automatically updates the corresponding tlb file (binary type library file) when the type library is saved For any changes to Interfaces and CoClasses that were created using a wizard, the Type Library editor also updates your implementation files For more information on using the Type Library editor to write interfaces and CoClasses, see Chapter 41,
“Working with type libraries.”
When to use type libraries
It is important to create a type library for each set of objects that is exposed to external users, for example,
• ActiveX controls require a type library, which must be included as a resource in the DLL that contains the ActiveX controls
• Exposed objects that support vtable binding of custom interfaces must be
described in a type library because vtable references are bound at compile time Clients import information about the interfaces from the type library and use that information to compile For more information about vtable and compile time binding, see “Automation interfaces” on page 43-13
• Applications that implement Automation servers should provide a type library so that clients can early bind to it
• Objects instantiated from classes that support the IProvideClassInfo interface, such
as all descendants of the VCL TTypedComObject class, must have a type library.
• Type libraries are not required, but are useful for identifying the objects used with OLE drag-and-drop
When defining interfaces for internal use only (within an application) you do not need to create a type library