Wednesday 24 June 2009

Modify your programs

First, we'll create an MDI type of application:

Here are the steps:

1. Create a new MDI application. You can even use the MDI Application wizard (File - New - Other - Projects - MDI Application).
2. Make sure FormStyle property of the main form is set to fsMDIForm.
3. Add a main menu to the application. Let it have one item - the one that loads the MDI child from the Package.

MDI module parent
4. Make sure you build the application using run-time packages. Go to Project-Options, select the Packages tab, and check the "Build with run-time packages". You should at least use the rtl and the vcl package.

Project-Options - built with packages

Before writing some actual Delphi code, let's first build the package and add one MDI child form to it.

1. Start by creating a run-time package.
2. Add a TForm object to the package. Make sure FormStyle property is set to fsMDIChild.
3. Add one exported procedure to create an instance of the child form:

procedure TPackageMDIChildForm.FormClose
(Sender: TObject;
var Action: TCloseAction);
begin
//since this is an MDI child, make sure
//it gets closed when the user
//clicks the x button.
Action := caFree;
end;

procedure ExecuteChild;
begin
TPackageMDIChildForm.Create(Application);
end;

exports
//NOTE!! The export name
//is CASE SENSITIVE
ExecuteChild;

end.

Going back to the MDI host application...

Here's the entire code in the main MDI form:

type
//signature of the "ExecuteChild"
//procedure from the Package
TExecuteChild = procedure;

TMainForm = class(TForm)
...
private
PackageModule : HModule;
ExecuteChild : TExecuteChild;
procedure PackageLoad;
end;

var
MainForm: TMainForm;

implementation
{$R *.dfm}

procedure TMainForm.PackageLoad;
begin
//try loading the package
//(let's presume it's in the same
//folder, where the main app. exe is)
PackageModule := LoadPackage('MDIPackage.bpl');

//if loaded, try locating
//the ExecuteChild procedure
if PackageModule <> 0 then
try
@ExecuteChild := GetProcAddress(PackageModule,
'ExecuteChild');
except
//display an error message if we fail
ShowMessage ('Package not found');
end;
end;

//menu click
procedure TMainForm.mnuCallFromDLLClick
(Sender: TObject);
begin
//lazzy load package
if PackageModule = 0 then PackageLoad;

//if the ExecuteChild procedure
//was found in the package, call it
if Assigned(ExecuteChild) then ExecuteChild;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
//if the package was loaded,
//make sure to free the resources
if PackageModule <> 0 then
UnloadPackage(PackageModule);
end;

The above code, dynamically loads (PackageLoad procedure) the package as needed (when menu item is selected) and unloads the package when the application terminates. If you need help with the code, check the "Dynamic Form in Dynamic Package" article.

Finally, at run time, we have an MDI child form loaded from a package and working happily inside an MDI parent form:

Packaged MDI Child form inside an MDI parent

One final note: when modularizing applications using run-time packages, you have to redistribute the required packages along with the application's exe file.

That's it! As simple as it can be.
Related Articles

* A Beginner’s Guide to Delphi Programming - Chapter 11
* Your First MDI Delphi Project
* MDI Development in Delphi. Part I.
* MDI Development in Delphi. Part II.
* Dynamic World of Packages - page 1/3

Zarko Gajic
Guide since 1998

Zarko Gajic
Delphi Programming Guide

* Sign up for my Newsletter

* My Blog
* My Forum