2, dynamic link to the MFC DLL
Let's first look at an example before discussing a DVL status problem of dynamic links to the MFC. This example can be accomplished by the following steps:
1) In the VC menu, File-> New has newly created an engineering of the MFC AppWizard named Dllshared, the next step Select Regular DLL Using Shared MFC DLL.
2) Add a dialog resource in the project, which ID is: IDD_ABOUTBOX. And change the value of IDD_aboutbox to 100 among resource.h.
3) Define the following functions in dllshared.cpp:
void showdlg ()
{
CDIALOG DLG (IDD_ABOUTBOX);
Dlg.domodal ();
}
4) Add a line in the Exports statement in the dllshared.def file: showdlg to export the ShowDLG function.
5) Compilation to generate dllshared.dll and dllshared.lib.
Continue to use the above USE project to copy the previously generated dllshared.dll and dllshared.lib two files to the project's debug directory, and will
EXTERN "C" __Declspec (dllexport) void showdlg ();
#pragma comment (lib, "debug / dllstatic))
These two rows are changed to:
Void showdlg ();
#pragma comment (Lib, "Debug / Dllshared")
Compile and run Use.exe. Click the button, what did you see this time? Yes, it's right, this time you pop up the dialog box for use.exe. The DLL type of the above example is changed to the MFC Extension DLL (Using Shared MFC DLL) also occurs.
Why do you have the above problem? This is because when the MFC shared library is used, by default, the MFC uses the resource handle of the primary application to load the resource template. Although we call the function in the DLL to display the dialog box in the DLL, and the corresponding dialog template is stored in the DLL, but the MFC is still in the primary application to find the corresponding dialog template in Use.exe. Since the dialog resource ID defined in the DLL is the same as the resource ID defined in the primary application, the MFC is displayed in the main application's regarding the dialog box. If the two are different, the MFC thinks that the dialog resource defined in the DLL does not exist, and DLG.Domodal will return 0, which is nothing.
So how do I solve the above problem? The solution is to switch when appropriate, to ensure that modules with the current state are the modules we need to use the correct resources. The MFC provides the following functions and macro to complete these work:
AfxgetStaticModuleState: This is a function, its function prototype is:
AFX_MODULE_STATE * AFXAPI AFXGETSTAICMODULESTATE ();
This function constructs an instance PModuleState of the AFX_Module_State class on the stack and returns it after assigning it. In the constructor of the AFX_Module_State class, this class gets the pointer to the current module state and stores it in the member variable, and sets the PModuleState to a new valid module state. In its destructor, this class reduces the pointer stored in its member variable to the previous module status of storage.
AFX_MANAGE_STATE: This is a macro, its prototype:
AFX_MANAGE_STATE (AFX_MODULE_STATE * pModuleState) This macro is used to pModuleState (points to a global data module is a module structure pointer AFX_MODULE_STATE state) as the current instant action space (the remainder of the immediate containing scope) of the active module status. When leaving the role of the included macro, the previous valid module state is automatically restored.
AFXGETRESOURCEHANDLE: The prototype of this function is:
Hinstance AfxgetResourceHandle ();
This function returns a handle of the module that saves the Hinstance type, the application defaults to the resource loaded with the resource.
AFXSETRESOURCEHANDLE: The prototype of this function is:
Void AfxSetResourceHandle (Hinstance HinstResource);
This function sets the modules represented by HinstResource to modules with current status.
The module status can be switched in the DLL of the MFC by using the above four functions or macros. Next we will introduce how to use the above four functions or macros by modifying the examples above. Let's take a look at the Regular DLL Using Shared MFC DLL Type:
In the first statement of the showdlg function of the third step of the above example, add the following statement (to ensure the first row of the statement):
AFX_MANAGE_STATE (AFXGETSTATICModuleState ());
Then recompile to generate dllshared.dll and dllshared.lib, and re-copy the two files to the debug directory of the USE project. This time you build us.exe and run, click the button, you can see the dialog that we join in the DLL, no longer is the dialog box about USE.exe.
Through the above explanation, I believe that you already know the role of this statement. After the first line of the function showdlg plus this, the MFC library automatically switches the current module status each time the application uses the function, so that the correctness of the resource read is guaranteed.
AFX_Manage_State (AFXGETSTAICMODULESTATE ()); is automatically switched to switch the current module status, or by manually switching the current module status by using the AFXGETRESourceHandle and AfxSetResourceHandle. The specific usage is as follows:
In the first statement of the showdlg function of the third step of the above example, add the following statement (to ensure the first row of the statement):
Hinstance Save_HINSTANCE = AFXGETRESOURCEHANDLE ();
AFXSetResourceHandle (THEAPP.M_HINSTANCE);
After the dialog is successful, it is DLG.Domodal (); after adding:
AFXSetResourceHandle (Save_HINSTANCE);
This method is obtained and saves the handle of the current state module after entering the ShowDLG function. The handle of the DLL module is then obtained (of course, you can also use the getModuleHandle function to get the handle of the DLL module) and use the AFXSetResourceHandle function to set it to the current state. Finally, use the restore the AFXSetResourceHandle resource handle after calling the dialog, recover the current module status.
Do something troubles, but a little benefit is that you can restore the resource handle immediately after completing the task of using the resource. And AFX_Manage_State (AFXGetStaticModuleState ()); method can only resume the resource handle after the function of the function is completed. Since the executable file must be heavy and other reasons, it is recommended that it is necessary to resume the resource handle, otherwise many problems may be encountered. For example, if the user moves the DLL dialog, at this time, the resource handle still has a resource of the DLL, then the program will crash. The time when the best recovery handle is in response to the WM_INITDIALOG message, because the template of the dialog is already read. For the MFC DLL of the MFC Extension DLL (Using Shared MFC DLL), the method of switching the current module status is similar to the method used by the Regular DLL Using Shared MFC DLL type MFC DLL, which is no longer implemented. The different places are as follows:
Using AFX_manage_state (AFXGETSTAICModuleState ()) in the MFC extension DLL, the following error is generated:
MFCS42D.LIB (DLLMODUL.OBJ): Error LNK2005: __PRAWDLLMAIN Already Defined in DLLEXTEND.OBJ
MFCS42D.LIB (DLLMODUL.OBJ): Error LNK2005: _dllmain @ 12 Already Defined in Dllextend.obj
MFCS42D.LIB (DLLMODUL.OBJ): Error LNK2005: __PRAWDLLMAIN Already Defined in DLLEXTEND.OBJ
Therefore, AFX_Manage_State () is required in the MFC extended DLL; replace it to AFX_Manage_State ()); can switch the current module status.
The method used by AFXGETRESOURCEHANDLE and AFXSetResourceHandle in the MFC extension DLL is the same as those used in the MFC DLL of the Regular DLL Using Shared MFC DLL type. Also, the handle of the DLL module can be obtained by the HMODULE member of the DLGEXTENTDLL provided by the MFC. That is, use AFXSetResourceHandle (DLGEXTENTDL.HMODULE);
Of course, for dynamic links to the MFC's DLL, you can switch the current state module in the MFC application that calls the DLL. The handle of the DLL module can be obtained with a getModuleHandle function. Not described herein.
Continued: Use resources in DLL (1)
---------- Rivershan Original in 2004.3.8, please indicate the source