Thursday, October 16, 2008
Delphi plugin by example
One of the top asked questions in Delphi newsgroups is how to place a form contained in a Dll into our application forms. This method allows to create pluggable applications, easier to maintain and customize.
To accomplish our task, first of all we'll create a Dll using File -> New -> Other -> Dll Wizard. Delete the comment aboud memory managment then Save the Dll as "dllform.dpr".
Now create a form inside the Dll with File -> New -> Form. Go to the Object Inspector and change the name of the new form to MyDllForm then add some controls like buttons, labels and everything you want, then remove the "var Form1: TForm1;" reference, you don't need it. Save the form as "myform".
Go back to the Dll source by going to Project -> View Source, and look at the uses clause, a reference to the recently created form unit must be there. Try to compile by hitting Ctrl + F9, if anything fails, re-check the previous paragraphs.
Adding exportable code
As you can't export a Form directly, you must create an exportable function who can export your form class.
Go to your form's source and add just above the "implementation" section, this code:
The main form
Create a new application by going to File -> New -> VCL Forms Application. This creates a new application with a main form called Form1. Go to the form and add a TButton and a TPanel.
Why a TPanel?, whell, the TPanel will contain the form we'll load from the Dll. You can use a TPageControl with a TTabSheet instead, or any other container.
Now we'll add a couple of private fields in the TForm1 class:
After that, double click on the TButton to add the code needed to call the exported function in the Dll and create an instance of TMyForm:
You can download a sample project from here.
To accomplish our task, first of all we'll create a Dll using File -> New -> Other -> Dll Wizard. Delete the comment aboud memory managment then Save the Dll as "dllform.dpr".
Now create a form inside the Dll with File -> New -> Form. Go to the Object Inspector and change the name of the new form to MyDllForm then add some controls like buttons, labels and everything you want, then remove the "var Form1: TForm1;" reference, you don't need it. Save the form as "myform".
Go back to the Dll source by going to Project -> View Source, and look at the uses clause, a reference to the recently created form unit must be there. Try to compile by hitting Ctrl + F9, if anything fails, re-check the previous paragraphs.
Adding exportable code
As you can't export a Form directly, you must create an exportable function who can export your form class.
Go to your form's source and add just above the "implementation" section, this code:
// To get a reference of your form's classThen create the body of MyFormClass function, go below the "implementation" section and write this:
TMyFormClass = class of TMyDllForm;
// To be able to export the form class.
function MyFormClass: TFormClass; stdcall; export;
function MyFormClass: TFormClass; stdcall;Now, you must tell your library what functions to export. This is easy, just go to Project -> View Source and add this before the "end.":
begin
Result := TMyDllForm;
end;
exportsBefore compiling be sure to activate "Build with Runtime Packages" in Project -> Options -> Packages. When you click the checkbox, a ton of packages separated by a comma appears just below, leave only the "vcl" package.
MyFormClass;
The main form
Create a new application by going to File -> New -> VCL Forms Application. This creates a new application with a main form called Form1. Go to the form and add a TButton and a TPanel.
Why a TPanel?, whell, the TPanel will contain the form we'll load from the Dll. You can use a TPageControl with a TTabSheet instead, or any other container.
Now we'll add a couple of private fields in the TForm1 class:
Now we'll implement a method to dynamically load the Dll. Go to the Form1, then to the Object Inspector -> Events and double click on "OnCreate" and "OnDestroy" to create these two events, then write this code inside them:
private
FLoadedForm: TForm;
FLibHandle: Cardinal;
procedure TForm5.FormCreate(Sender: TObject);
begin
FLibHandle := LoadLibrary('dllform.dll');
end;
procedure TForm5.FormDestroy(Sender: TObject);
begin
FLoadedForm.Free;
FreeLibrary(FLibHandle);
end;
After that, double click on the TButton to add the code needed to call the exported function in the Dll and create an instance of TMyForm:
procedure TForm1.Button1Click(Sender: TObject);Again, before compiling remember to enable "Build with Runtime Packages", as you did when compiling the Dll. If you don't do this, an "Cannot assign a TFont to a TFont" error will be raised when you click Button1.
type
TMyFormClass = function: TFormClass; stdcall;
var
lMyFormClass: TMyFormClass;
begin
if not Assigned(FLoadedForm) then
begin
lMyFormClass := GetProcAddress(FLibHandle, 'MyFormClass');
if @lMyFormClass <> nil then
begin
// Create a TMyForm instance (not visible)
FLoadedForm := lMyFormClass.Create(nil);
// Place the Panel from TMyForm in Panel1
FLoadedForm.Controls[0].Parent := Panel1;
end;
end;
end;
You can download a sample project from here.