EvoCorp Home    Advanced Delphi Development Home

 

 

   

 

Active Documents

Update
September 15, 2006: Because a lot of people have been asking for an Active Document sample, I have finally included one, here. This sample provides a basic active document server that allows you to display your own user interface when a document of type "*.axdoc" is opened from within Internet Explorer.

Have you ever wondered how non-HTML documents, such as those belonging to Microsoft Word or Adobe Acrobat can be viewed through Internet Explorer, or how Microsoft Excel documents can be embedded interactively within a Microsoft Word document?

The answer lies in ActiveX Document Servers, or active documents. One of my recent projects revolved around the implementation of an active document server because, apart from strategic business reasons, this represented an interesting challenge as a developer. However in the quest for information on developing active documents using Delphi I discovered that whilst there is ample documentation available in the C++ language, there is no readily available equivalent for Delphi.

This lead me to create my own basic ActiveX Document Server class.

I needed an active document class that could associate itself with a specific MIME type, a class that would be interactively loaded when connecting to a specific document type from within Internet Explorer. As a result I developed a class whose primary purpose was to provide the basic mechanics required by all active documents, and one that could readily extend itself to other, more complex active document controls.

This code demonstrates the following:

  How to implement the IOleDocument and IOleDocumentView interfaces, the primary interfaces required for implementation of an OLE document.
  How to implement the IOleObject and IOleInPlaceObject interfaces, required for interaction with the parent container.
  How to implement the class factory associated with your OLE document, including automated association of your class with a specific MIME type and file extension.
  Registration of your ActiveX Document Server as a downloadable class, preventing the "Some files can harm your computer..." message from being displayed by Internet Explorer when connecting to your document.

Despite it's positives, this class does not show how to implement the following:

  How to perform menu merging with the container
  How to implement a toolbar within your object
  How to implement persistent streams for custom saving and loading of document information

These items might well be included somewhere down the track, however in the mean time Microsoft have an MSDN sample showing how to do these things in C++, available here (if this link fails, please contact me).

How do I create a new document server?

NOTE: Before starting, you will need to change the declaration of TActiveXControl.InPlaceActivate (declared in AxCtrls.pas) from:

function InPlaceActivate(ActivateUI: Boolean): HResult;
   --to--
function InPlaceActivate(ActivateUI: Boolean): HResult; virtual;

I understand that editing Delphi source is (a) not recommended and (b) a nuisance, and as such I apologize in advance for this. This is, however, the solution that I came up with and what's more, it works.

One of the most common questions I get regard this unit is “what do I have to do to create a new document server?” Although commonsense, the most important thing you need to have when creating an active document server is a thorough understanding of both COM and how to create ActiveX libraries in Delphi!

Because document servers rely on class identifies to identify the object responsible for viewing a particular type of data, the first step in creating a new active document server is to create a new ActiveX Library.

The second step is to create a new Unit. Not a new ActiveX control or Active Form, just a new unit. This unit will contain your active document server class which must inherit from TActiveDocServer (defined in AxDocServer.pas) and will implement the user interface for your document. This unit must also create an instance of the TActiveDocServerFactory class (also defined in AxDocServer.pas), responsible for defining the files associated with your document server and registering that information accordingly.

The following as an example of the unit you would create:

 

unit MyDocServerUnit;
interface
uses
  SysUtils, Windows, Classes, Controls, ActiveX, ComObj, ComServ, AxDocServer;

type
  IMyDocumentServer = interface
  [GUID]
    // Define your interface requirements here, or through
    //
Delphi’s type library editor.
  end;

 
TMyUserInterface = class;

  TMyDocServer = class(TActiveDocServer,
    IMyDocumentServer, IOleCommandTarget)
  // Class implementation
  private
    FUserInterface: TMyUserInterface;
    ...
    ...
  public
    procedure Initialize; override// Used to reparent the user interface.
    ...
  end;

  TMyUserInterface = class(TForm)
    // Class implementation
    // Just an ordinary everyday form, nothing special, created
    // via the "File|New|Form" menu (VCL, not .NET). This form
    // will contain all of your user interface and should not
    // contain a border or border icons.
    ...
 
end;

implementation
  ...
initialization
  // Create a new active document server factory instance, which is responsible
  // for registering your class against a file extension and identifying it as the class
  // responsible for displaying documents of this type.

  TActiveDocServerFactory.Create(
    ComServer,
TMyDocServer, CLASS_MyDocumentServer, '.myserver',
    'application/my-server'
, '', 0, 131473,
    DOCMISC_CANCREATEMULTIPLEVIEWS, tmApartment);

end.

TActiveDocServer defines a property called "Container", a TPanel VCL control that acts as your ActiveX container. This enables you to create an ordinary form (such as TMyUserInterface, above) that contains your user interface which, at runtime, you manually create and reparent to Container, for example:

  procedure TMyDocServer.Initialize;
  begin
    inherited;
    FUserInterface := TMyUserInterface.Create(Container);
    FUserInterface.Parent := Container;
    FUserInterface.Align := alClient;
    FUserInterface.Visible := True;
    ...

  end;
   

Requirements

HLink.pas, available here.


As stated above, before starting you will need to change the declaration of TActiveXControl.InPlaceActivate (declared in AxCtrls.pas) from:

function InPlaceActivate(ActivateUI: Boolean): HResult;
   --to--
function InPlaceActivate(ActivateUI: Boolean): HResult; virtual;

Honestly I wouldn't use this code unless you have Delphi 6 (or later). Other than that there are no special requirements for using this code, although it is highly recommended that you read up on ActiveX Document Servers BEFORE attempting to create one yourself :)

Download Code

September 15, 2006: The ActiveX Document Server sample can be downloaded, here.

AxDocServer.pas can be downloaded here.

HLink.pas can be downloaded here.

Adobe Acrobat is a registered trademark of Adobe Systems Incorporated.
ActiveX is a registered trademark of Microsoft Corporation.
Microsoft Internet Explorer is a registered trademark of Microsoft Corporation.
Microsoft Excel and Microsoft Word are registered trademarks of Microsoft Corporation.