By Gladys Hall,2014-03-02 05:17
9 views 0

How To Write Delphi Wizards

    发信人: strayli (stray), 信区: Delphi

     : How To Write Delphi Wizards(1)

    发信站: BBS 水木清华站 (Thu Nov 5 21:59:25 1998) WWW-POST

     How To Write Delphi Wizards



     Delphi and C++Builder are truly open development environments, in that they

    have interfaces to enable us to integrate our own tools and experts within

    their IDE. This article will focus on writing and integrating Wizards (previously called Experts) with Delphi. The resulting (32-bits) Wizards will

    be compatible with Delphi 2.0x, Delphi 3 and C++Builder. Delphi has four kinds of Wizards: Project Experts, Form Experts, Standard

    Experts and (32-

    bits only) AddIn Experts. The first two can be found in the Repository, Standard Experts can be found under the Help menu (like the

    Database Form Expert), while AddIn Experts have to provide their own menu-

    interface with the Delphi IDE (typicaly anywhere in the menu except for

    the Help Menu, which seems to be reserved for Standard Experts only). Project and Form Experts can be activated whenever you create a new Project

    or Form (just like Project and Form Templates). Standard and AddIn Experts

    are the other kind of Wizards that generally do not create a new project or

    form, but provide some kind of information, or only create a new file



    If you've ever tried an Wizard, you know what power and ease they can


    to you. The Project Expert develops an entire project for you based on your

    preferences (like for example the Application Wizard). The Fspecific


    Experts develop custom forms that are added to your current project.


    Database Form Expert, for example, generates a form that displays data from

    an external database. These example Wizards are not just external tools that

    can be started from Delphi, they actually communicate with Delphi and

     are an

    integrated part of the development environment. While this is not so strange

    for the existing Delphi Experts (after all, they were developed and a

     dded by

    the same team that developed Delphi in the first place, and we all know

    Delphi's IDE is written in Delphi), it sounds intriguing at least to know

    that we, too, can write a Delphi Wizard that is able to communicate with

    Delphi in the same way. Could we actually write an Wizard that also opens

    files in the IDE, that can be used to start a new project from scratch? Yes, all this is possible, and more, as we will see


    1. TIExpert Interface

    The major reason why everybody thinks writing custom Wizards is difficult, is

    because they are not documented. Not in the manuals or on-line Help, that is

    (they are documented in my book The Revolutionary Guide to Delphi 2 and in my

    column in The Delphi Magazine). If you take a look at the documentation and

    source code on your harddisk, you'll find some important files and even two

    example Wizards that are installed automatically by Delphi itself. The

    important example files can be found in the DOC, SOURCE\VCL or SOURCE\TOOLSAPI subdirectories, and the main files are EXPTINTF.PAS, TOOLINTF.PAS, VIRTINTF.PAS and SHAREMEM.PAS. The first one shows how to

    derive and register our own Wizard, while the second one shows how to

     use the

    tool-services of Delphi to make the integration with the IDE complete. In order to start working on a custom wizard, we have to take a look at the

    abstract base class definition TIExpert in EXPTINTF.PAS, which is as follows

    for the 32-bits versions of Delphi:


     TExpertStyle = (esStandard, esForm, esProject, esAddIn);

     TExpertState = set of (esEnabled, esChecked);

     TIExpert = class(TInterface)


     { Expert UI strings }

     function GetIDString: string; virtual; stdcall; abstract;

    function GetName: string; virtual; stdcall; abstract;

     function GetAuthor: string; virtual; stdcall; abstract;

     function GetStyle: TExpertStyle; virtual; stdcall; abstract;

     function GetMenuText: string; virtual; stdcall; abstract;

     function GetState: TExpertState; virtual; stdcall; abstract;

     function GetGlyph: HICON; virtual; stdcall; abstract;

     function GetComment: string; virtual; stdcall; abstract;

     function GetPage: string; virtual; stdcall; abstract;

     { Launch the Expert }

     procedure Execute; virtual; stdcall; abstract;


    2. TGenericExpert: Hello, World!

    If we want to derive our own Wizard, say TGenericExpert, we have to derive it

    from the abstract base class TIExpert, which has seven or nine abstract

    member functions (GetStyle, GetName, GetComment, GetGlyph, GetState, GetIDString and GetMenuText, and for the 32-

    bits versions of Delphi also

    GetAuthor and GetPage) and one member procedure Execute. Since TIExpert is an

    abstract base class, we need to override every function we need for any

    particular Wizard.

    unit Generic;



     Windows, ExptIntf;


     TGenericExpert = class(TIExpert)


     { Expert Style }

     function GetStyle: TExpertStyle; override;

     { Expert Strings }

     function GetIDString: string; override;

     function GetName: string; override;

     function GetAuthor: string; override;

     function GetMenuText: string; override;

     function GetState: TExpertState; override;

     function GetGlyph: HICON; override;

     function GetComment: string; override;

     function GetPage: string; override;

     { Expert Action }

     procedure Execute; override;


     procedure Register;




    { The implementation details of TGenericExpert will follow in the text }

     procedure Register;



     end {Register};


    Let's have a closer look at our generic Wizard from this listing. Since

    TIExpert is an abstract base class, we need to override every function we

    need for our TGenericExpert. First of all, we need to specify the style of

    the Wizard with the GetStyle method that can return one of three (or four)

    possible values: esStandard to tell the IDE to treat the interface to


    Wizard as a menu item on the Help menu, esForm to tell the IDE to treat this

    Wizard interface in a fashion similar to form templates, or esProject

     to tell

    the IDE to treat this interface in a fashion similar to project templates.

    For 32-

    bits Delphi Wizards only, we can also return esAddIn here, to indicate

    that this is a special klind of Wizard that handles all its own interfaceing

    to the IDE through the TIToolServices interface. For our TGenericExpe

rt, a

    Standard type Wizard that only shows a MessageDlg to say hello to the


    we can use the esStandard style.

     function TGenericExpert.GetStyle: TExpertStyle;


     Result := esStandard

     end {GetStyle};

    The GetIDString should be unique to all Wizards that could be installed. By

    format of the string is: CompanyName.ExpertFunction, convention, the


    Borland.Expert or DrBob.GenericExpert.

     function TGenericExpert.GetIDString: String;


     Result := 'DrBob.TGenericExpert'

     end {GetIDString};

    After we've set the style of the Wizard, all we need to do is fill the other

    options accordingly. The GetName must return a unique descriptive name

    identifying this Wizard, like 'Generic Wizard'.

     function TGenericExpert.GetName: String;


     Result := 'Generic Wizard'

     end {GetName};

    If the style is esForm or esProject, then - for 32-

    bits versions of Delphi

    only -

     we need to return a valid name for the Author. In this case, the style

    is esStandard, so we can return an empty string instead. For an esForm or

    esProject style Wizard the name would be displayed in the Object Repository

    of the 32-bits versions of Delphi.

    {$IFDEF WIN32}

     function TGenericExpert.GetAuthor: String;


     Result := 'Bob Swart (aka Dr.Bob)' { although not needed for esStandard


     end {GetAuthor};


    If style is esForm or esProject then GetGlyph should return a handle to a

    bitmap (for Delphi 1) or icon (for Delphi 2.0x and 3) to be displayed

     in the

    form or project list boxes or dialogs. This bitmap should have a size


    60x40 pixels in 16 colours. The icon should be 32x32 in 16 colours. Again,

    since the style is just esStandard for our TGenericExpert, we can return 0

     can even combine the 16- and 32-here. We

    bit version of GetGlyph here (0 is a

    valid value to indicate that an icon or bitmap is empty). Note that if we

     a 0 when a bitmap or icon is needed, Delphi will use the defaureturn



    {$IFDEF WIN32}

     function TGenericExpert.GetGlyph: HICON;


     function TGenericExpert.GetGlyph: HBITMAP;



     Result := 0 { not needed for esStandard }

     end {GetGlyph};

    If style is esForm or esProject then GetComment should return a 1 or 2 line

    sentence describing the function of this Wizard. Since the style is esStandard, we can return an empty string.

     function TGenericExpert.GetComment: String;


     Result := '' { not needed for esStandard }

     end {GetComment};

    If style is esForm or esProject then - only for 32-

    bits versions of Delphi -

    using GetPage we can specify the name of the page in the Object Repository

    where to place our Wizard. If we don't specify a name here, then the Wizard

    just gets added to the Default Form or Project page. Since we're writing an

    esStandard Expert, we don't need to supply a page name, so we can return an

    empty string again.


     function TGenericExpert.GetPage: String;


     Result := '' { not needed for esStandard }

     end {GetPage};


    If style is esStandard then GetMenuText should return the actual text


    display for the menu item, like 'Generic Wizard'. Since this function


     time the parent menu is pulled-called each

    down, it is even possible to

    provide context sensitive text.

     function TGenericExpert.GetMenuText: String;


     Result := '&Generic Wizard...'

     end {GetMenuText};

    If the style is esStandard then GetState returning esChecked will cause the

    menu to display a checkmark. This function is called each time the Wizard is

    shown in a menu or listbox in order to determine how it should be displayed.

    We just leave it esEnabled for now.

     function TGenericExpert.GetState: TExpertState;


     Result := [esEnabled]