Using the Invokamatic Wizard eXtreme Toy

By: Dave Nottage

Abstract: This article shows how to use the Invokamatic Wizard that comes with the Delphi 6 eXtreme Toys. By Dave Nottage.

This article describes how to install and use the Invokamatic Wizard with Delphi. For a full description on how to build a complete Web service, please refer to Nick Hodges's excellent article, here. Daniel Polistchuck also describes Invokamatic in his article on the community site, for Web sessions in Web services.

Installing the Invokamatic Wizard

Registered users of Delphi 6 can download the Invokamatic Wizard here. Once you have downloaded the Zip file, extract the contents to a suitable directory.

Next, use File | Open:

File|Open

This opens the package (InvWiz.dpk) in the package editor:

Package Editor - Invokable Wizard

Click the Compile button and click Install to install the wizard.

Creating an invokable class

From the Delphi 6 main menu, Click File | New | Other, and select the Web Services tab of the Gallery dialog:

Gallery - WebServices - Invokable Wizard

Click OK. This will bring up the Invokable Interface & Class Wizard dialog. At this point, you will be naming what is essentially your Web service, so choose a name that reflects what your Web service actually does. MP3Finder, StockQuote, and MilesToMillimetresConverter are pretty good names.

Type the name in the Name To Use field. You'll notice as you type that other controls automatically populate.

You can change the unit identifier if you don't like what is automatically generated. The convention for unit names is that the unit containing the interface is suffixed with Intf and the unit that contains the implementation is suffixed with Impl. You can change these names if you wish by using File | Save As. You can have Invokamatic generate a single file for the interface and implementation by checking the Generate One File checkbox; however, if you are also creating a client, having separate units can reduce the amount of code in the client, as it will require the interface code only.

If you want your invokable class to be created when the service is called and destroyed when the call is completed, derive your class from TInvokableClass by selecting it from the drop down box:

Invokable Wizard Dialog - TInvokableClass

If you want to control the lifetime management of your invokable class, derive from TInterfacedObject by selecting it from the dropdown list, or type a class name that you have already defined elsewhere. The class you derive from must implement the methods of IInterface or be derived from a class that does.

Once you're accustomed to creating Web services, you might wish to exclude the automatically generated comments. You can do this by unchecking the Generate Comments checkbox.

Here is the implementation unit code generated for an invokable class that is derived from TInvokableClass:

{ Invokable implementation declaration unit for TRandomNumberGenerator,
  which implements IRandomNumberGenerator }

unit RandomNumberGeneratorImpl;

interface

uses
  RandomNumberGeneratorIntf, InvokeRegistry;

type
  TRandomNumberGenerator = class(TInvokableClass, IRandomNumberGenerator)
    // Make sure you have your invokable logic implemented in IRandomNumberGenerator
    // first, save the file, then use CodeInsight(tm) to fill in this
    // implementation section by pressing Ctrl+Space, marking all the interface
    // declarations for IRandomNumberGenerator, and pressing Enter.
    // Once the declarations are inserted here, use ClassCompletion(tm)
    // to write the implementation stubs by pressing Ctrl+Shift+C
  end;

implementation

initialization
  InvRegistry.RegisterInvokableClass(TRandomNumberGenerator);

end.

Here is the implementation unit code generated for an invokable class that is derived from TInterfacedObject:

{ Invokable implementation declaration unit for TRandomNumberGenerator,
  which implements IRandomNumberGenerator }

unit RandomNumberGeneratorImpl;

interface

uses
  RandomNumberGeneratorIntf, InvokeRegistry;

type
  TRandomNumberGenerator = class(TInterfacedObject, IRandomNumberGenerator)
    // Make sure you have your invokable logic implemented in IRandomNumberGenerator
    // first, save the file, then use CodeInsight(tm) to fill in this
    // implementation section by pressing Ctrl+Space, marking all the interface
    // declarations for IRandomNumberGenerator, and pressing Enter.
    // Once the declarations are inserted here, use ClassCompletion(tm)
    // to write the implementation stubs by pressing Ctrl+Shift+C
  end;

implementation

procedure RandomNumberGeneratorFactory(out Obj: TObject);
begin
  Obj := TRandomNumberGenerator.Create;
end;

initialization
  InvRegistry.RegisterInvokableClass(TRandomNumberGenerator, RandomNumberGeneratorFactory);

end.

Note the factory method. RandomNumberGeneratorFactory creates an instance of TRandomNumberGenerator. When the SOAP service creates an instance of this object, it obtains an IRandomNumberGenerator interface reference to the object, so when the reference falls out of scope, the object is freed. If you want the object to stay "alive" while the SOAP service is still loaded (in an ISAPI DLL that remains loaded in the Web server, for instance) you will need to use an additional reference at the unit level:

implementation

var
  FGenerator: TRandomNumberGenerator;
  FGeneratorInterface: IRandomNumberGenerator;

procedure RandomNumberGeneratorFactory(out Obj: TObject);
begin
  if FGenerator = nil then
  begin
    FGenerator := TRandomNumberGenerator.Create;
    {save a reference to the interface so that the global instance doesn't free itself }
    FGeneratorInterface := FGenerator as IRandomNumberGenerator;
  end;
  obj := FGenerator; { return global instance }
end;

The same will apply for classes that use a factory method, and derive from something other than TInterfacedObject.

Adding methods to your Web service:

The next task is to add your Web service's method declarations to the interface. As per the comments that are inserted automatically into the interface unit, you'll need to declare your methods with a calling convention, usually of stdcall.

An example interface:

type
  IRandomNumberGenerator = interface(IInvokable)
    ['{6261DD3C-B6DC-4ED3-8C3C-4E1045B432C2}']
    function Random: Extended; stdcall;
    function RandomRange(AFrom, ATo: Integer): Integer; stdcall;
    function RandG(Mean, StdDev: Extended): Extended; stdcall;
  end;

OK. The interface is defined -- now it's time to complete the implementation. Pressing Ctrl-Space inside the class definition brings up a list of the interface methods. Use the cursor-down key to multi-select:

Interface Class Completion

Press Enter. Here's what the class declaration looks like:

type
  TRandomNumberGenerator = class(TInvokableClass, IRandomNumberGenerator)
  public
    function Random: Extended; stdcall;
    function RandomRange(AFrom, ATo: Integer): Integer; stdcall;
    function RandG(Mean, StdDev: Extended): Extended; stdcall;
  end;

Use Delphi's class completion feature (Ctrl-Shift-C) to create the skeleton for the implementation methods, then add your code!

implementation

uses
  Math;

{ TRandomNumberGenerator }

function TRandomNumberGenerator.RandG(Mean, StdDev: Extended): Extended;
begin
  Result := Math.RandG(Mean, StdDev);
end;

function TRandomNumberGenerator.Random: Extended;
begin
  Result := System.Random;
end;

function TRandomNumberGenerator.RandomRange(AFrom, ATo: Integer): Integer;
begin
  Result := Math.RandomRange(AFrom, ATo);
end;

initialization
  Randomize;
  InvRegistry.RegisterInvokableClass(TRandomNumberGenerator);

end.
Adding your invokable class to your SOAP server

To add the new invokable class to your SOAP server, simply include the implementation unit name in the project's uses clause:

library RandomService;

uses
  WebBroker,
  RandomNumberGeneratorImpl,
  ISAPIThreadPool, // comment this line out when not using IIS
  ISAPIApp,
  SOAPWM in 'SOAPWM.pas' {wmSOAP: TwmSOAP};

{$R *.RES}

exports
  GetExtensionVersion,
  HttpExtensionProc,
  TerminateExtension;

begin
  Application.Initialize;
  Application.CreateForm(TwmSOAP, wmSOAP);
  Application.Run;
end.

There we have it! The Invokable Wizard may not do all that much, but at least it saves some typing time. I wrote the first cut of the wizard, John Kaster enhanced it, and Allen Bauer and Dave Wilhelm helped out in regards to the Open Tools API.

Happy wizarding!

Dave Nottage is CTO of Pure Software Technology, a software development company specializing in Delphi. He can be reached at dave@b3.com.au and the company's Web site is https://www.puresoftwaretech.com.


Server Response from: ETNASC03