Glover logo

Writing Extensions in Delphi


Home Glovers Contact Form

Pegasus Mail

Pegasus Mail Pmail Features

Pmail Extensions

Populist Delphi (1) Delphi (2) Dos Email

Digital Cameras

Digital images Renumber images Slideshows


Online Databases Access & ASP Access & PHP Mysql & ASP Mysql & PHP

Pegasus Mail Extensions using Delphi forms.

This page describes the development of the same simple Composer extension as Pmtmplt, but using Delphi in the conventional manner with Forms and the Application Object. The advantage of this approach, for an experienced Delphi programmer, is the speed with which modifications can be made. The project, called PmtpltF, compiles to a 173KByte PmtpltF.DLL file under Delphi 2.01, taking less than 3 seconds on a Pentium machine under NT4. Although I feel this is rather large file to offer from a web site, PMail's Extension Manager loads it in less than 2 seconds on the same machine.

The source files

These may be downloaded by clicking PmtpltF.EXE . This is a self-extractor file containing the following source files:-


These files are extracted by typing pmtpltf.exe <Enter> at the DOS prompt. The files should be placed in a convenient directory and the project PMTPLTF loaded into Delphi 2. The two files WPMFORMS.INC and WPMPREFS.INC , should also be added to the same directory. Select Delphi's menu item Project | Options and set the output directory to be the same as that containing WINPMAIL.EXE and compile the project.

The Forms Fact file, PMTPLTF.FFF should be made by pasting the following 8 lines using Notepad, saving the file in the same directory as WINPMAIL.EXE

Form name = "Minimal Delphi 2 Extn."
32-bit model = 1
Form DLL = ~a\tmp\PMTPLTF.dll
Form type = COMPOSER
Form flags = 0
Form tagname = PMtpltF
Form data = ""

When PMTPLTF.FFF and the compiled PMTPLTF.DLL are in WINPMAIL.EXE's directory, start WINPMAIL.EXE and select the PmtpltF (named: Minimal Delphi 2 Extn.) Extension. A dialog window appears with 3 edit controls - for the To:, Subject: and Message body fields of an email - and a button labeled Process. Fill in the 3 fields and click the process button. This will queue the email message for sending, in exactly the same way as Pegasus's regular New Mail editor dialog. Apart from a few small differences in appearance - eg the colour of the extension's dialog - this extension looks and feels the same as the generic Pmtmplt Extension described earlier. (It can compose emails with long bodies - up to 2GBytes perhaps, although I've not tested it beyond 120Kbytes.)

The following sections describe how to create the extension DLL from scratch.

Description of the Delphi 2.01 Extension

Listings of the .DPR project file and .PAS unit file are shown below. The DFM file comprising the list of properties of the extension's window is not listed here, but is contained in the PmtpltF.EXE self-extracting file.

  (* -------start of pmtpltF.dpr file -------*)
 library PmtpltF;

  Windows,  Messages,  Graphics,  Controls,  Forms,  Dialogs,
  SysUtils,  Classes,{ WPMForms, }
  TpltU in 'TpltU.pas' { Form1};

function FORMINIT(  Version : Word;  Vari : Integer;   hParent : hWND; Data : PChar;
        var hDialog : HWND;  { var} CallBack_Name : PChar): WORD; export; stdcall;
      { Save the extension managers window }
   PegParent := hParent;

   CallBack_Name := Nil;

      { Create Form1 - the Extension's dialog window}
      { and pass Form's handle to Pegasus }
   Application.CreateForm(TForm1, Form1);
   hDialog := Application.MainForm.Handle;

      { Return sucess }
   FORMINIT := 1;

   FORMINIT index 1;

  (* -------end of pmtpltF.dpr file   -------*)
  (* ------ start of tpltU.pas file--------- *)
unit TpltU;
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs, { WPMForms, } StdCtrls, ExtCtrls;

   TForm1 = class(TForm)
    Panel1: TPanel;
    ToEdit: TEdit;
    SubjEdit: TEdit;
    SendBtn: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    MsBody: TMemo;
   procedure CreateParams(  var Params : TCreateParams  );override;
    procedure SendEmail(Sender: TObject);
    procedure MsbodyKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);

 { Pegasus message handlers, see for description of WM_FM_* messages }
procedure FmInit(  var Msg : TMessage  ); message WM_FM_INIT;
procedure FmWhereYaWannIt(  var Msg : TMessage  ); message WM_FM_WHEREYAWANNIT;
procedure FmSize(  var Msg : TWMSize  ); message WM_FM_SIZE;
procedure WMInitFocus(  var Msg : TMessage  ); message WM_FM_INITFOCUS;
{ procedure FmCommand(  var Msg : TMessage  ); message WM_FM_COMMAND; }
     { Public declarations }
  Form1     : TForm1;
  Msg : TMessage;
  PegParent : HWND;

{$R *.DFM}

procedure TForm1.CreateParams(  var Params : TCreateParams  );
   inherited CreateParams(  Params  );
   with Params do
         {TForm1's style must be set to WS_CHILD  overriding any
          BorderIcons and BorderStyle properties set in Object 

      Style := WS_CHILD;

         {Set the parent's window handle to that of the Pegasus
          MDI child window}
      WndParent := PegParent;

procedure TForm1.FmInit(  var Msg : TMessage  );
  {Let Pegasus decide when to show the Extension's window }

procedure TForm1.WMInitFocus(  var Msg : TMessage  );
  {Let Pegasus decide when to show the Extension's window }

procedure TForm1.FmWhereYaWannIt(  var Msg : TMessage  );
Var C: ^TPoint;
  c := Pointer(Msg.LParam);
  c^.x := 0;
  c^.y := 0;
  {Return 1 to align extension's top left corner}
   Msg.Result := 1;

procedure TForm1.FmSize(  var Msg : TWMSize  );
      {Simply resizes Pegasus' MDI child window}
   MoveWindow(Form1.Handle,  0,  0,  Msg.Width,  Msg.Height,  true  );

{procedure TForm1.FmCommand(  var Msg : TMessage  );
  (* optional code here *)
end; }

procedure TForm1.SendEmail(Sender: TObject);

Var P: PChar;

   SendMessage(PegParent, WM_F_SETSTATUS, 3, Longint( PChar('Specifying 

Message.') ));
   if SendMessage(PegParent, WM_F_NEWMESSAGE, 0, 0) = 0 then
        MessageBox(0 , ' WM_F_NEWMESSAGE has failed', 'Message',mb_OK);
     SendMessage(PegParent, WM_F_SETDEFAULTS, 0, 0);
     P:= PChar(ToEdit.Text   + #0);
     SendMessage(PegParent, WM_F_TO,          0, Longint(P) );
     P:= Pchar(SubjEdit.Text + #0);
     SendMessage(PegParent, WM_F_SUBJECT,     0, Longint(P) );
     P:= PChar(MsBody.Text   + #0);
     SendMessage(PegParent, WM_F_MESSAGETEXT, 0, Longint(P) );
     SendMessage(PegParent, WM_F_SENDMESSAGE, 0, 0);
end; {SendEMAIL}

{The following method is needed to add the linefeed character (Ctrl-L 

-ie #10)}
{For some reason, TMemo components in Pegasus Extensions don't 

{VK_RETURN keycodes to Carriage Return, Linefeed}

procedure TForm1.MsbodyKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
if key = VK_RETURN then
   SendMessage(MsBody.Handle, WM_CHAR, 10, 0);
(* -----end of tpltU.pas file -------*)

Notes on the coding

The listing above applies to 32 bit versions of the extension, compiled with Delphi 2.01 for use with 32bit versions of Pegasus Mail. 16 bit versions of the extension can be made by replacing the FORMINIT function header statement in the DPR file. ie replace:-

function FORMINIT(Version : Word;  Vari : Integer;   hParent : hWND; Data : PChar;
       var hDialog : HWND;  { var} CallBack_Name : PChar): WORD; export; stdcall;
with the following (ommitting the stdcall directive):-
function FORMINIT(Version : Word;  Vari : Integer;   hParent : hWND; Data : PChar;
       var hDialog : HWND;  { var} CallBack_Name : PChar): WORD; export;

The handle of PMail's child window (hParent) is saved in the global variable PegParent - declared in TpltU.PAS.

In the unit file, TForm1's CreateParams method sets the style of the form to WS_CHILD as required by Extensions Modeless Dialog windows. This method overrides any properties set during forms design in Delphi's Object Inspector.

The privately declared message response methods such as:-

procedure FmInit( var Msg : TMessage ); message WM_FM_INIT; 

respond to messages sent from PMail to the extension. The Msg VAR parameter will often be of the usual Delphi TMessage type, but in FmSize for example, where receipt of the message, WM_FM_SIZE is intended to have exactly the same effect as the WM_SIZE Windows API message, casting the Msg parameter as TWMSize enables the MoveWindow() function call to be written as:-

MoveWindow(Form1.Handle, 0, 0, Msg.Width, Msg.Height, true );

rather than:-

MoveWindow (hWindow, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE); 

The SendEmail procedure is similar to the procedure coded in the generic program Pmtmplt.dpr, but with a few important differences imposed by Delphi 2.01's conventions. The Text property of TMemo and TEdit is now defined as TCaption which is of the "string" type. In Delphi 2 the string type applies to dynamically stored long strings of indefinite length (not limited to 255 characters as in previous Turbo Pascal or Borland Pascal). Instances of variables of type string, and therefore of type TCaption, contain text strings which are terminated in ASCII nuls (#0 in BP7 and Delphi). Furthermore such variables can be typecast to PChar without requiring the StrPCopy() function. Accordingly SendEmail was coded to take advantage of these features.

The MsbodyKeyDown() method, which inserts a newline (ASCII 0xOA) character, was found to be needed to cause a newline to appear in the MsBody Memo field when the Enter key is pressed. If this method is omitted, pressing the Enter key has no visible effect on the text entered - although the usual equivalent, Ctrl-M does. (I have only noticed this behaviour in PMail extensions using Delphi Forms.)


This page describes a simple demo Pegasus Mail Extension for composing emails and sending them to Pegasus's send queue. The only advantage it might be said to have over the regular New Mail window found in PMail Versions up to 2.54, is that emails having unlimited message body fields can be composed. This feature stems from the non-segmented 32bit addresses provided in the 32bit version of MicrosoftWindows.

The Delphi system with its object-oriented Forms, run-time type information and visual components provides for rapid development of Pegasus Extensons. The large size (170Kbytes plus in Delphi2 and even greater in Delphi1) is however a significant drawback