Plug-in programming in Delphi

Source: Internet
Author: User

The programming of the plug-in structure requires a plug-in container to control the running status of each DLL and arrange each sub-system into a dll library file. For each DLLProgramYou need to reserve interface functions for the container. General interface functions include: Start the function of calling the dll library, and close the function of the dll library. Through interface functions, plug-in containers can pass parameters to the DLL module for dynamic control. I will explain the implementation details below and give a responseCode.

You may need to first understand the unit structure and engineering structure in Delphi. This article did not discuss the theoretical details of DLL programming in depth, but demonstrated some practical code. I learned the book "Delphi deep programming" by Liu Yi.

I am also in the early stage of Delphi, but I think there are some points worth discussing in this DLL development, so I will write this articleArticleI hope you will give me some generous suggestions on poor things.

Introduction to sample programs

To facilitate reading, I will use some program code of a MIS system to demonstrate some plug-in programming methods. The example program is a typical c/s structured DBMS application. The focus is on the control statements of the Framework Program (Hall) and the Response Control of the DLL plug-in program.

1. Program Structure

The plug-in container Hall is created using an independent project. The main window of hall serves as the MDI container form in the MDI program. Hall will explicitly call the interface functions in the DLL.
Each plug-in program uses its own project independently. Different from a common project, the DLL project creates a DLL wizard, and the corresponding compiled files are suffixed with DLL.

2. Interface Design

In the instance program Narcissus, we reserve two interface functions:

Showdllform

This function transfers the application handle to the DLL subwindow. The DLL program dynamically creates an instance of the DLL form. Some business logic can also be passed to the DLL subwindow in the form of parameters, such as the form name and the user name currently logged in. This function is used to create a DLL form instance for the first time.

Freedllform

This function will display the release DLL window instance. When you exit the application, call the freedllform method of each DLL form to release the created instance. Otherwise, the memory read-only error will occur. Similarly, some business logic that needs to be done when the form is released can be passed to the DLL form in the form of parameters.

3. debugging method

The DLL form program cannot be executed directly. A plug-in container is required to call the program. In this example, you must first implement a basic hallprogram, and then save hall.exe in a fixed directory. Set each DLL project as follows:

1) Open the DLL Project

2) Select Run-parameters.

3) view our container hall.exe in the pop-up window

In this way, the hall program will be automatically called when the DLL program is debugged, And the DLL program will be debugged using the call interface reserved in Hall.

Basic Implementation of plug-in programs

The DLL program design method is not very different from the general winapp, but all windows are saved in the dll library as a special "resource" and need to be called manually, unlike winapp, a project is automatically created. The method for declaring an interface function is simple.

1) Declare the function in implementation of Unit

2) Add the stdcall mark at the end of the function declaration statement.

3) use the exports statement to declare the function interface before the begin statement of the project-View Source.

To make the code concise, I personally like to add a separate unit (file-new -- unit) in the project, and then define all the function bodies to be output in this unit, do not forget to include the unit of the referenced form in uses. I named this unit unitentrance. In the showdllform function, I initialized the window to be displayed and called the show Method for display. Hall will pass the login user name with parameters, after obtaining the user name, you can perform some permission control, as shown in interface initialization.

The Code is as follows:

Unit unitofficeentrance;

Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms;
Function showdllform (ahandle: thandle; acaption: string; auserid: string): Boolean; stdcall;
Function freedllform (ahandle: thandle; acaption: string; auserid: string): Boolean; stdcall;
Implementation
Uses unitofficialmainform; // change it to the unit of mainform.
VaR
Dll_form: tformofficialmain; // change it to the name of mainform.

//-----------------------------------------
// Name: showdllform
// FUNC: The DLL plug-in calls the entry function.
// Para: handle of the ahandle program; acaption the title of this form
// Rtrn: N/
// Auth: CST
// Date: 2005-6-3
//-----------------------------------------

Function showdllform (ahandle: thandle; acaption: string; auserid: string): Boolean;
Begin
Result: = true;
Try
Application. Handle: = ahandle; // hook to the main program container
Dll_form: = tformofficialmain. Create (application); // change the name of mainform.
Try
With dll_form do
Begin
Caption: = acaption;
Statusbar. Panels. items [0]. Text: = auserid;
// Configure UI
Show;
End;
Except
On E: exception do
Begin
Dll_form.free;
End;
End;
Except
Result: = false;
End;
End;

//-----------------------------------------
// Name: freedllform
// FUNC: The DLL plug-in calls the exit function.
// Para: ahandle hook program handle
// Rtrn: True/false
// Auth: CST
// Date: 2005-6-11
//-----------------------------------------

Function freedllform (ahandle: thandle; acaption: string; auserid: string): Boolean;
Begin
Application. Handle: = ahandle; // hook to the main program container
If dll_form.showing then dll_form.close; // if the window is opened, the form. closequery can be disabled.
If not dll_form.showing then
Begin
Dll_form.free;
Result: = true;
End // The status is still on, indicating closequery. canclose = false
Else
Begin
Result: = false;
End;
End;
End.

The DLL project file code is as follows:

Library official;

{Important Note about dll Memory Management: sharemem must be

First unit in your library's uses clause and your project's (select

Project-View Source) uses clause if your DLL exports any procedures or

Functions that pass strings as parameters or function results. This

Applies to all strings passed to and from your DLL -- even those that

Are nested in records and classes. sharemem is the interface unit

The borlndmm. dll Shared Memory Manager, which must be deployed along

With your DLL. To avoid using borlndmm. dll, pass string Information

Using pchar or parameter string parameters .}

Uses

Sysutils,

Classes,

Unitofficialdetailform in 'unitofficialdetailform. pa' {formofficialdetail },

Unitofficialmainform in 'unitofficialmainform. pa' {formofficialmain },

Unitofficeentrance in 'unitofficeentrance. pa ',

Unitofficialclass in '... \ public \ library \ unitofficialclass. pa ',

Unitmydataadatper in '... \ public \ library \ unitmydataadatper. pa ',

Unitmyheaders in '... \ public \ library \ unitmyheaders. pa ';

{$ R *. Res}

Exports showdllform, freedllform; // interface function

Begin

End.

Once the DLL window is called by the plug-in program, the window instance will be kept at the upper layer of the hall window, so there is no need to worry about blocking.

Container Program Implementation

1. Introduction of interface functions

The functions in the dll library can be called either explicitly or implicitly. Explicit calling is more flexible, so we use explicit calling. In Delphi, You need to declare the function type for the interface function and then instantiate the function type instance. This instance is actually a pointer to the function, with pointers, we can access the function, PASS Parameters, and obtain the return value. The declaration of adding a function class to the interface part of the unit file:

Type

// Define the interface function type. The interface function comes from the DLL interface.

Tshowdllform = function (ahandle: thandle; acaption: string; auserid: string): Boolean; stdcall;

Tfreedllform = function (ahandle: thandle; acaption: string; auserid: string): Boolean; stdcall;

The following steps are required to display the function called:

1) load the dll library file

2) obtain the function address

3) execute the Function

4) release the dll library

Next, we will discuss these steps in detail.

2. Load the dll library file

By calling the API function loadlibrary, you can load the dll library into the memory. Here we will not discuss the impact of DLL on memory management. The loadlibrary parameter is the DLL file address path. If the file is loaded successfully, a cardinal type variable is returned as the dll library handle; if the target file does not exist or the DLL file fails to be loaded due to other causes, a value of 0 is returned.

3. instantiate interface functions

The API function that obtains the interface function pointer is getprocaddress (library file handle, function name). If the function is found, the pointer of the function is returned. If the function fails, the NIL is returned.
Use the function type defined above to define the function pointer variable, and then use the @ operator to obtain the function address, so that you can use the pointer variable to access the function. The main code is as follows:

......
VaR
Showdllform: tshowdllform; // DLL interface function instance
Freedllform: tfreedllform;
Begin
Try
Begin
Aplugin. procaddr: = loadlibrary (pchar (Spath ));
Aplugin. funcfreeaddr: = getprocaddress (aplugin. procaddr, 'freedllform ');
Aplugin. funcaddr: = getprocaddress (aplugin. procaddr, 'showdllform ');

@ Showdllform: = aplugin. funcaddr;
@ Freedllform: = aplugin. funcfreeaddr;
If showdllform (self. Handle, aplugin. Caption, aplugin. userid) then
Result: = true
......

4. A specific implementation method

For structured management plug-ins to facilitate system expansion in the future, we can record available DLL information in the database, and then dynamically access the DLL program by querying database records.

1) system module table Design

For the MIS system, you can use the existing DBS condition to create a system module table, record the DLL file and Related Information mapped to the system module.

Field name Function Type
Autoid index int
The modalias module is also called varchar.
Modname Module name varchar
The unique varchar ID of the modwndclass form
Modfile dll path varchar
Modmemo remarks text

· The Module name is used for unified naming rules in the programming design stage, especially for reference by team members during development.

· The Module name will be passed as the acaption parameter to the showdllform function as the title of the DLL window.

· The unique form identifier is the classname of the main window in the DLL submodule, which is used to determine the window to be controlled during running.

· The dll path stores the DLL file name, which will be converted to an absolute path in the program.

2) Plug-in Information Data Structure

You can define a data interface that records plug-in information to centrally control the DLL plug-in. Add the following code to the interface:

Type

// Define the plug-in Information Class

Tmyplugins = Class
Caption: string; // DLL form title
Dllfilename: string; // DLL file path
Wndclass: string; // Form ID
Userid: string; // User Name
Procaddr: thandle; // library handle loaded by loadlibrary
Funcaddr: pointer; // showdllform function pointer
Funcfreeaddr: pointer; // freedllform function pointer
End;

......

Create a tmyplugins instance for each plug-in. The following describes how to initialize these instances.

3) Load Functions by plug-ins

In this example, the DLL window is loaded and displayed in the events that trigger opening the subwindow in Hall. After a button event is triggered, check whether the DLL has been loaded Based on the plug-in struct instance. If the DLL has been loaded, display or close the control window; if it is not loaded, access the data table and assign the fields to the plug-in structure. Then, load and obtain the pointer.

The local code is as follows:

......
//-----------------------------------------

// Name: openplugin

// FUNC: plug-in information class control process: initialization = Set permissions = load the DLL window

// Para: aplugin-tmyplugins; salias alias; ifuncvalue permission Value

// Rtrn: N/

// Auth: CST

// Date: 2005-6-2

//-----------------------------------------

Procedure tformhall. openplugin (afromactn: taction; aplugin: tmyplugins; salias: string; suserid: string );
VaR hwndplugin: hwnd;
Begin

// Determine whether the plug-in window has been loaded with hwndplugin: = findwindow (pchar (aplugin. wndclass), nil );
If hwndplugin <> 0 then // The plug-in window has been loaded
Begin
If not iswindowvisible (hwndplugin) then
Begin
Afromactn. Checked: = true;
Showwindow (hwndplugin, sw_showdefault); // display
End
Else
Begin
Afromactn. Checked: = false;
Showwindow (hwndplugin, sw_hide );
End;
Exit; // exit the plug-in creation process
End;

// Initialize a plug-in instance

If not initializemyplugins (aplugin, salias) then
Begin
Showmessage ('initialization plug-in class error. ');
Exit;
End;

// Obtain the current permission Value

Aplugin. userid: = suserid;
// Load the DLL window

If not loadshowpluginform (aplugin) then
Begin
Showmessage ('loading center plug-in error. ');
Exit;
End;
End;

// initialize
// name: initializemyplugins
// FUNC: Initialize the myplugin instance (Caption | dllfilename | isloaded)
// para: aplugin-tmyplugins
// rtrn: N/A
/auth: CST
// Date: 2005-6-2
// ---------------------------------------

Function tformhall. initializemyplugins (aplugin: tmyplugins; salias: string): Boolean;
VaR
Strsql: string;
Myda: tmydataadapter;
Begin
Result: = false;
Myda: = tmydataadapter. Create;
Strsql: = 'select * From systemmodulelist where modalias = '+ quotedstr (salias );
Try
Myda. retrievedata (strsql );
Except
On E: exception do
Begin
Result: = false;
Myda. Free;
Exit;
End;
End;
Try
Begin
With myda. mydataset do
Begin
If not isempty then
Begin
Aplugin. Caption: = fieldbyname ('modname'). value;
Aplugin. dllfilename: = fieldbyname ('modfile'). value;
Aplugin. wndclass: = fieldbyname ('dwndclass'). value;
Result: = true;
End;
Close;
End; // end of with... do...
End; // end of try
Except
On E: exception do
Begin
Result: = false;
Myda. Free;
Exit;
End; // end of exception
End; // end of try... Skip t

Myda. Free;
End;

//-----------------------------------------

// Name: loadshowpluginform

// FUNC: load the DLL plug-in and display the window

// Para: aplugin-tmyplugins

// Rtrn: True-creation successful

// Auth: CST

// Date: 2005-6-2

//-----------------------------------------

Function tformhall. loadshowpluginform (const aplugin: tmyplugins): Boolean;

VaR
Showdllform: tshowdllform; // DLL interface function instance
Freedllform: tfreedllform;
Spath: string; // full path of the DLL file
Begin
Try
Begin
Spath: = extractfilepath (application. exename) + 'ins ins \ '+ aplugin. dllfilename;
Aplugin. procaddr: = loadlibrary (pchar (Spath ));
Aplugin. funcfreeaddr: = getprocaddress (aplugin. procaddr, 'freedllform ');
Aplugin. funcaddr: = getprocaddress (aplugin. procaddr, 'showdllform ');
@ Showdllform: = aplugin. funcaddr;
@ Freedllform: = aplugin. funcfreeaddr;
If showdllform (self. Handle, aplugin. Caption, aplugin. userid) then
Result: = true
Else
Result: = false;
End;
Except
On E: exception do
Begin
Result: = false;
Showmessage ('loading plug-in module error. Check whether the files in the Plugins directory are complete. ');
End;
End;
End;

......

4) DLL window control

As the code in 3) shows, opening and closing the DLL window is only at the presentation layer. closing the window does not actually release the DLL window, only call the API function findwindow according to the window ID (that is, form. name) to obtain the form handle. Use the ncmdshow parameter of the showwindow function to control the display/hide of the window.

In fact, this is a poor implementation of this program. If you use the self. Close method in the DLL window, it will cause a memory error, and there is no way to solve the problem due to limited capacity. Therefore, this is the best practice. Therefore, the close button of the Main Window of each DLL program must be hidden.

5) Release of DLL Library

When the program exits, the dll library must be released one by one based on the plug-in information instance. The function for releasing the dll library is as follows:

Procedure tformhall. closeplugin (aplg: tmyplugins );
VaR
Freedllform: tfreedllform;
Begin
If aplg. procaddr = 0 Then exit;
If aplg. funcfreeaddr = nil then exit;
@ Freedllform: = aplg. funcfreeaddr;
If not freedllform (application. Handle, '','') then
Showmessage ('err ');
End;

Summary

The running effect of this instance is as follows:


In my above methods, because there are a lot of problems that cannot be solved due to limited capabilities, some seemingly unreasonable methods have been adopted, I hope that you can design a better solution after a few attempts, and I hope to learn more.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.