Dynamic Loading


Dynamic loading, also known as runtime dynamic linking, is a more versatile and more complex method of loading DLLs. Dynamic linking allows you to load and unload a dynamic link library whenever you want without having to create an import unit.

To dynamically load a DLL, you have to:

  1. Declare a procedural variable or a procedural type that describes the routine that you want to call.

  2. Call the LoadLibrary function to load the DLL.

  3. Call the GetProcAddress function to retrieve a pointer to the routine in the DLL.

  4. Call the routine.

  5. Call the FreeLibrary function to unload the DLL.

Now we're going to create a new DLL that contains VCL forms and exports overloaded routines. First, create a new DLL (optionally name it FormLib) and then create and export a routine that dynamically creates and displays an empty form (see Listing 21-4). In case you forgot, you have to add the Forms unit to the DLL's uses list in order to work with VCL forms.

Listing 21-4: A DLL routine that creates and displays an empty form

image from book
library FormLib; uses   SysUtils, Classes, Forms; {$R *.res} procedure ShowDLLForm; begin   with TForm.Create(Application) do   try     ShowModal;   finally     Free;   end; end; exports   ShowDLLForm; begin end.
image from book

Now that you have the DLL, add a new VCL Forms project to the project group and drop a button on the Designer Surface. We're going to dynamically load the image from book FormLib.dll in its OnClick event handler.

The first thing you have to do is declare a procedural variable that has the same parameter list as the routine you want to call. Since the ShowDLLForm routine in the image from book FormLib.dll has no parameters, you have to declare a variable of type procedure. It does sound weird, but that is what you have to do. Here's the declaration of the procedural variable that we're going to use:

procedure TMainForm.ShowFormButtonClick(Sender: TObject); var   DLLRoutine: procedure; begin end;

To load the DLL, you have to call the LoadLibrary function and pass the DLL's file name as the lpLibFileName parameter. If the function succeeds, it returns the DLL's handle. You must store the function's return value because you can't unload the DLL or locate the routines in the DLL without its handle. Here's the portion of code that calls the LoadLibrary function:

procedure TMainForm.ShowFormButtonClick(Sender: TObject); var   DLLRoutine: procedure;   DLLHandle: THandle; begin   DLLHandle := LoadLibrary('FormLib.dll'); end;

Before going any further, let's create a try-finally block that will make sure the DLL is unloaded even if an error occurs. To unload the DLL from memory, call the FreeLibrary function and pass the DLL's handle as the hLibModule parameter:

procedure TMainForm.ShowFormButtonClick(Sender: TObject); var   DLLRoutine: procedure;   DLLHandle: THandle; begin   DLLHandle := LoadLibrary('FormLib.dll');   try   finally      FreeLibrary(DLLHandle);   end;            // try..finally end;

The only thing left to do is to call the GetProcAddress function in the try block to retrieve the address of the ShowDLLForm routine. The GetProcAddress function accepts two parameters: the DLL's handle and the name of the routine you want to locate.

DLLRoutine := GetProcAddress(DLLHandle, 'ShowDLLForm');

Before calling the routine pointed to by the DLLRoutine variable, you should check whether the DLLRoutine variable points to a valid address because GetProcAddress returns nil if it can't find the specified routine in the DLL.

The following listing shows how to call a routine from a dynamically loaded DLL.

Listing 21-5: Calling a procedure from a dynamically loaded DLL

image from book
 procedure TMainForm.ShowFormButtonClick(Sender: TObject); var   DLLRoutine: procedure;   DLLHandle: THandle; begin   DLLHandle := LoadLibrary('FormLib.dll');   try     { DLLRoutine points to ShowDLLForm in FormLib.dll' }     DLLRoutine := GetProcAddress(DLLHandle, 'ShowDLLForm');     { call the ShowDLLForm procedure }     if Assigned(DLLRoutine) then       DLLRoutine     else       MessageDlg('The specified routine cannot be found.',         mtInformation, [mbOk], 0);   finally     FreeLibrary(DLLHandle);   end;       // try..finally end;
image from book

The result of the code in Listing 21-5 is shown in Figure 21-4.

image from book
Figure 21-4: Dynamically loading a DLL

If you execute the code in Listing 21-5, you'll see that the ShowDLLForm procedure works properly and displays the empty form onscreen, but it also displays a Taskbar button for the form.

To remove the Taskbar button, you have to pass the calling application's Application.Handle (or the main form's handle) to the DLL and assign it to the DLL's Application.Handle property before creating the form in the DLL (see Listing 21-6).

Listing 21-6: Linking the DLL with the host application

image from book
library FormLib; uses   Windows, SysUtils, Classes, Forms,   SampleFrm in 'SampleFrm.pas' {VCLForm}; {$R *.res} procedure ShowDLLForm; overload; begin   with TForm.Create(Application) do   try     ShowModal;   finally     Free;   end; end; procedure ShowDLLForm(HostHandle: THandle); overload; var   OrigHandle: THandle;   DLLName: array[0..255] of Char; begin   OrigHandle := Application.Handle;   try     { link with the host application }     Application.Handle := HostHandle;     VCLForm := TVCLForm.Create(Application);     try       { extract the DLL's file name }       GetModuleFileName(HInstance, DLLName, 255);       { display the DLL and the host application's file names on the form }       VCLForm.Label1.Caption := 'DLL: ' + ExtractFileName(DLLName);       VCLForm.Label2.Caption := 'Host: ' +         ExtractFileName(Application.ExeName);       VCLForm.ShowModal;     finally       VCLForm.Free;     end;   finally     Application.Handle := OrigHandle;   end;       // try..finally end; exports   ShowDLLForm,   ShowDLLForm(HostHandle: THandle) name 'ShowDLLFormEx'; begin end.
image from book

As you can see, the code in Listing 21-6 also illustrates how to export overloaded routines. When exporting an overloaded routine, include its parameter list in the exports list and change its name using the name directive.

To call the overloaded ShowDLLForm routine that accepts the THandle parameter, you have to create another procedural variable with the same parameter list and call it by the name specified with the name directive (in this case, ShowDLLFormEx). This code is displayed in Listing 21-7.

Listing 21-7: The proper way to display a VCL form that resides in the DLL

image from book
procedure TMainForm.ShowFormButton2Click(Sender: TObject); var   DLLRoutine: procedure(HostHandle: THandle);   DLLHandle: THandle; begin   DLLHandle := LoadLibrary('FormLib.dll');   try     { DLLRoutine points to ShowDLLFormEx in FormLib.dll' }     DLLRoutine := GetProcAddress(DLLHandle, 'ShowDLLFormEx');     { call the ShowDLLFormEx procedure }     if Assigned(DLLRoutine) then       DLLRoutine(Handle) { pass the form's handle }     else       MessageDlg('The specified routine cannot be found.',         mtInformation, [mbOk], 0);   finally     FreeLibrary(DLLHandle);   end;       // try..finally end;.
image from book

The result of this updated code for displaying VCL forms that reside in a DLL is displayed in Figure 21-5.

image from book
Figure 21-5: Properly displaying VCL forms



Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net