This is the fourth part of "deep dive into VC ++ dynamic link library (DLL) programming". Before reading this article, read the first three parts: (1), (2) and (3 ).
The content of the MFC extension DLL is the extension of the MFC. You can use the MFC extension DLL just like using the DLL of the MFC itself. In addition to MFC extension DLL, the interface between the MFC extension DLL and the application can also be MFC. We generally use MFC extension DLL to include some enhanced functions of MFC, such as cstatic and cbutton extension of MFC to provide more powerful capabilities.
When you use the Visual C ++ Wizard to produce the MFC extension DLL, the MFC wizard automatically adds the DLL entry function dllmain:
Extern "C" int apientry
Dllmain (hinstance, DWORD dwreason, lpvoid lpreserved)
{
// Remove this if you use lpreserved
Unreferenced_parameter (lpreserved );
If (dwreason = dll_process_attach)
{
Trace0 ("mfcexpenddll. dll initializing! /N ");
// Extension DLL one-time Initialization
If (! Afxinitextensionmodule (mfcexpenddlldll, hinstance ))
Return 0;
// Insert this DLL into the resource chain
// Note: If this extension DLL is being implicitly linked to
// An MFC regular DLL (such as an ActiveX control)
// Instead of an MFC application, then you will want
// Remove this line from dllmain and put it in a separate
// Function exported from this extension DLL. The regular DLL
// That uses this extension DLL shoshould then explicitly call that
// Function to initialize this extension DLL. Otherwise,
// The cdynlinklibrary object will not be attached to
// Regular DLL's resource chain, and serious problems will
// Result.
New cdynlinklibrary (mfcexpenddlldll );
}
Else if (dwreason = dll_process_detach)
{
Trace0 ("mfcexpenddll. dll terminating! /N ");
// Terminate the library before Destructors are called
Afxtermextensionmodule (mfcexpenddlldll );
}
Return 1; // OK
}
The above code completes the initialization and termination of the MFC extension DLL.
Because the methods for exporting functions and variables using MFC extension DLL are no different from those of other DLL, we will not explain it in detail. The following example shows how to create an MFC extension DLL and call it in an application.
6.1 create an MFC extension DLL
Next we will export a button class csxbutton (cbutton class extended from MFC) in the MFC extension DLL. The class csxbutton is a class used to replace cbutton, it enables you to display bitmap and text on the same button, while the MFC button can only display one of them. The source code of the class csxbutton is widely spread on the Internet and has a good "Mass Basis". Therefore, using this class to explain the special functions of the MFC extension DLL has.
MFC contains some macros, which are expanded in different ways in the DLL and the application that calls the DLL, so that in the DLL and application, A unified macro can be used to indicate the differences between output and input:
// For Data
# Ifndef afx_data_export
# Define afx_data_export _ declspec (dllexport)
# Endif
# Ifndef afx_data_import
# Define afx_data_import _ declspec (dllimport)
# Endif
// For Classes
# Ifndef afx_class_export
# Define afx_class_export _ declspec (dllexport)
# Endif
# Ifndef afx_class_import
# Define afx_class_import _ declspec (dllimport)
# Endif
// For global APIs
# Ifndef afx_api_export
# Define afx_api_export _ declspec (dllexport)
# Endif
# Ifndef afx_api_import
# Define afx_api_import _ declspec (dllimport)
# Endif
# Ifndef afx_ext_data
# Ifdef _ afxext
# Define afx_ext_class afx_class_export
# Define afx_ext_api afx_api_export
# Define afx_ext_data afx_data_export
# Define afx_ext_datadef
# Else
# Define afx_ext_class afx_class_import
# Define afx_ext_api afx_api_import
# Define afx_ext_data afx_data_import
# Define afx_ext_datadef
# Endif
# Endif
Export a class and use afx_ext_class directly in the class declaration header file. The following is an example of exporting the csxbutton class:
# Ifndef _ sxbutton_h
# DEFINE _ sxbutton_h
# Define sxbutton_center-1
Class afx_ext_class csxbutton: Public cbutton
{
// Construction
Public:
Csxbutton ();
// Attributes
PRIVATE:
// Positioning
Bool m_buseoffset;
Cpoint m_pointimage;
Cpoint m_pointtext;
Int m_nimageoffsetfromborder;
Int m_ntextoffsetfromimage;
// Image
Hicon m_hicon;
Hbitmap m_hbitmap;
Hbitmap m_hbitmapdisabled;
Int m_nimagewidth, m_nimageheight;
// Color Tab
Char m_bcolortab;
Colorref m_crcolortab;
// State
Bool m_bdefault;
Uint m_noldaction;
Uint m_noldstate;
// Operations
Public:
// Positioning
Int setimageoffset (INT npixels );
Int settextoffset (INT npixels );
Cpoint setimagepos (cpoint P );
Cpoint settextpos (cpoint P );
// Image
Bool seticon (uint NID, int nwidth, int nheight );
Bool setbitmap (uint NID, int nwidth, int nheight );
Bool setmaskedbitmap (uint NID, int nwidth, int nheight, colorref crtransparentmask );
Bool hasimage () {return (bool) (m_hicon! = 0 | m_hbitmap! = 0 );}
// Color Tab
Void setcolortab (colorref crtab );
// State
Bool setdefaultbutton (bool bstate = true );
PRIVATE:
Bool setbitmapcommon (uint NID, int nwidth, int nheight, colorref crtransparentmask, bool busemask );
Void checkpointforcentering (cpoint & P, int nwidth, int nheight );
Void redraw ();
// Overrides
// Classwizard generated virtual function overrides
// {Afx_virtual (csxbutton)
Public:
Virtual void drawitem (lpdrawitemstruct );
//} Afx_virtual
// Implementation
Public:
Virtual ~ Csxbutton ();
// Generated message map Functions
Protected:
// {Afx_msg (csxbutton)
Afx_msg lresult ongettext (wparam, lparam );
//} Afx_msg
Declare_message_map ()
};
# Endif
Add the sxbutton. cpp file directly to the project, compile the project, and obtain the "mfcexpenddll. lib" and "mfcexpenddll. dll" files. We can use the depends tool that comes with Visual Studio to view this. dll and find that it has exported many symbols (see figure 15 ).
Figure 15 a large number of symbols exported when exporting a category (+ enlarge the image)
These are symbols processed by the compiler for class constructor, destructor, and other member functions and variables. We use _ declspec (dllexport) directly) the statement Declaration class exports these symbols.
If we want to use the. Lib file to export these symbols, it is very difficult. We need to generate the. map file in the project, query the symbols of the. map file, and then export them one by one. 16. Open the settings option of the DLL project, select link, and select generate map file to generate the. Map File.
Open the. map file generated by the mfcexpenddll project and we find that it contains the symbol (Symbol) shown in Figure 15)
0001: 00000380? Hasimage @ csxbutton @ qaehxz 10001380 f I sxbutton. OBJ
0001: 000003d0 ?? 0csxbutton @ Qae @ xz 100013d0 F sxbutton. OBJ
000:00000500 ?? _ Gcsxbutton @ uaepaxi @ Z 10001500 f I sxbutton. OBJ
0001: 00000570 ?? _ Ecsxbutton @ uaepaxi @ Z 10001570 f I sxbutton. OBJ
0001: 00000630 ?? 1csxbutton @ UAE @ xz 10001630 F sxbutton. OBJ
0001: 00000700? _ Getbasemessagemap @ csxbutton @ kgpbuafx_msgmap @ xz 10001700 F sxbutton. OBJ
0001: 00000730? Getmessagemap @ csxbutton @ mbepbuafx_msgmap @ xz 10001730 F sxbutton. OBJ
0001: 00000770? Redraw @ csxbutton @ aaexxz 10001770 f I sxbutton. OBJ
0001: 000007d0? Seticon @ csxbutton @ qaehihh @ Z 100017d0 F sxbutton. OBJ
................................................................................ // Omitted
Figure 16 generate a. Map File (+ enlarge the image)
Therefore, for the MFC extension DLL, we should not export the class using the. Lib file.
6.2 call of MFC extension DLL
Add a dllcall project in the DLL workspace. It is a dialog box-based MFC exe program. Add two buttons sxbutton1 and sxbutton2, and set the attributes to "owner draw" and "17.
Figure 17 set the button property to "owner draw"
Add two ICON resources to the project: idi_msn_icon (MSN icon) and idi_refbar_icon (Windows System icon ).
Modify the "calldlldlg. H" header file of the project:
# Include ".../mfcexpenddll/sxbutton. H" // export Class header file containing DLL
# Pragma comment (Lib, "mfcexpenddll. lib") // implicitly link the DLL
//////////////////////////////////////// /////////////////////////////////////
// Ccalldlldlg Dialog
Class ccalldlldlg: Public cdialog
{
// Construction
Public:
Ccalldlldlg (cwnd * pparent = NULL); // standard Constructor
// Dialog data
// {Afx_data (ccalldlldlg)
Enum {IDD = idd_calldll_dialog };
// Add member variables corresponding to the two buttons
Csxbutton m_button1;
Csxbutton m_button2;
...
}
Modify the "calldlldlg. cpp" file to associate the m_button1 and m_button2 member variables with the button controls in the dialog box:
Void ccalldlldlg: dodataexchange (cdataexchange * PDX)
{
Cdialog: dodataexchange (PDX );
// {Afx_data_map (ccalldlldlg)
Ddx_control (PDX, idc_button2, m_button2 );
Ddx_control (PDX, idc_button1, m_button1 );
//} Afx_data_map
}
Modify the bool ccalldlldlg: oninitdialog () function and add the code for setting icons for the two buttons:
Bool ccalldlldlg: oninitdialog ()
{
Cdialog: oninitdialog ();
// Add "about..." menu item to system menu.
// Idm_aboutbox must be in the system command range.
Assert (idm_aboutbox & 0xfff0) = idm_aboutbox );
Assert (idm_aboutbox <0xf000 );
Cmenu * psysmenu = getsystemmenu (false );
If (psysmenu! = NULL)
{
Cstring straboutmenu;
Straboutmenu. loadstring (ids_aboutbox );
If (! Straboutmenu. isempty ())
{
Psysmenu-> appendmenu (mf_separator );
Psysmenu-> appendmenu (mf_string, idm_aboutbox, straboutmenu );
}
}
// Set the icon for this dialog. The framework does this automatically
// When the application's main window is not a dialog
Seticon (m_hicon, true); // set big icon
Seticon (m_hicon, false); // set small icon
// Todo: add extra initialization here
M_button1.seticon (idi_msn_icon, 16, 16 );
M_button2.seticon (idi_refbar_icon, 16, 16 );
Return true; // return true unless you set the focus to a control
}
When you run the program, a dialog box of 18 is displayed, and images and text are displayed on the buttons at the same time. This indicates that the MFC extension DLL is called correctly.
Figure 18 dll extension buttons are displayed
If void ccalldlldlg: dodataexchange (cdataexchange * PDX) is not modified, the following code is not added:
Ddx_control (PDX, idc_button2, m_button2 );
Ddx_control (PDX, idc_button1, m_button1 );
You can also add the following code in the bool ccalldlldlg: oninitdialog () function to associate m_button1, m_button2 with idc_button1, and idc_button2:
M_button1.subclassdlgitem (idc_button1, this );
M_button2.subclassdlgitem (idc_button2, this );
However, the subclassdlgitem member functions of the ddx_control and button classes cannot exist at the same time; otherwise, an error occurs in the program.
6.3 conclusion
The above analysis shows that the export and reference methods of the MFC extension DLL are not much different from those described in the previous sections. The MFC extension DLL mainly emphasizes the Function Extension of the MFC. Therefore, if the objective of the DLL is not to enhance the function of the MFC, its interface with the application is not the MFC, do not create the DLL as the MFC extension DLL.
Download the source code of this article. (58.3kb, WinZip compression)
(By email: 21cnbao@21cn.com)