[Repost] Use resources in DLL (recommended)

xiaoxiao2021-03-06  59

Use resources in DLL

The most often seen about DLL is how to use dialogs in DLL, which is a very common problem with how to use resources in DLL. Here we analyze and solve this problem from both aspects of Win32 DLL and MFC DLL.

1. Win32 DLL

Using dialog box in Win32 DLL is simple, you only need to add dialog resources in your DLL, and you can set the control you need above on the dialog. Then use Dialogbox or CreateDialog to create a dialog box and define your own dialog box callback function to process the message received. By following a specific example, learn how to use the dialog box in Win32 DLL, follow these steps:

1) In the VC menu, File-> New New Win32 Dynamic-Link Library Project is named USEDLG, the next step Select A Simple DLL Project.

2) Insert-> Resource in the VC menu Add a IDD_DLG_SHOW Dialog resource, remove the CANCEL button on this Dialog, and only the OK button is left. Add another ID to IDD_ABOUTBOX dialog, which capens is About. Save this resource and name the resource file Usedlg.rc. And add resource.h and usedlg.rc to the project.

3) Contains Resource.h in usedlg.app, and add the following code:

Hinstance hinst = null;

HWND HWNDDLG = NULL;

Bool Callback DlgProc (HWND HDLG, UINT MESSAGE,

WPARAM WPARAM, LPARAM LPARAM;

Bool Callback AboutProc (HWND HDLG, UINT MESSAGE,

WPARAM WPARAM, LPARAM LPARAM;

EXTERN "C" __Declspec (dllexport) void showdlg ();

Bool apientry dllmain (Handle Hmodule,

DWORD UL_REASON_FOR_CALL,

LPVOID LPRESERVED

)

{

Switch (ul_reason_for_call)

{

Case DLL_Process_attach:

Hinst = (hinstance) hmodule;

Case DLL_PROCESS_DETACH:

Break;

}

Return True;

}

EXTERN "C" __declspec (dllexport) void showdlg ()

{

HWnddlg = createdialog (hinst, makeintresource (IDD_DLG_SHOW),

NULL, (DLGPROC) DLGPROC;

ShowWindow (hwnddlg, sw_show);

}

Bool Callback DlgProc (HWND HDLG, UINT MESSAGE,

WPARAM WPARAM, LPARAM LPARAM)

{

Switch (Message)

{

Case WM_INITDIALOG:

Return True;

Case WM_COMMAND:

IF (loword (wparam) == iDok)

Dialogbox (HinSt, makeintResource (IDD_ABOUTBOX),

HDLG, (DLGPROC) aboutProc);

Return True;

Case WM_Close:

DestroyWindow (HDLG); hwnddlg = NULL;

Return True;

}

Return False;

}

Bool Callback AboutProc (HWND HDLG, UINT MESSAGE,

WPARAM WPARAM, LPARAM LPARAM)

{

Switch (Message)

{

Case WM_Close:

EndDialog (HDLG, NULL);

HWnddlg = NULL;

Return True;

}

Return False;

}

4) Compile to generate usedlg.dll and usedlg.lib.

Next we establish an application that calls this DLL, the steps are as follows:

1) In the VC menu, File-> New has created a new MFC AppWizard (EXE) project named Use, and then click the finish button after you select Dialog Based.

2) Add a button on the main dialog, then double-click this button, pop up the Add Member Function dialog box, directly click OK to enter the void cusedlg :: onbutton1 () function. And add a function call to this function: showdlg () ;.

3) Follow the following code followed by the #include statement:

EXTERN "C" __Declspec (dllexport) void showdlg ();

#pragma comment (Lib, "Debug / UseDLG")

4) Copy the usedlg.dll and usedlg.lib generated above the Usedlg project to the debug directory of the USE project.

5) Compile to generate use.exe.

Run Use.exe, click the Button1 button, you can see a non-modular dialog box named Dialog. Click the button above to pop up the modal dialog. Run success.

Let's review the process of using the dialog box in Win32 DLL.

In DLL, we define two dialog resources: IDD_DLG_SHOW and IDD_ABOUTBOX, and export the function showdlg. The non-modular dialog IDD_DLG_SHOW is created using the CREATEDIALOG function in the function showdlg, and specifies the callback function DLGProc of the dialog. WM_INITDIALOG, WM_COMMAND, and WM_CLOSE messages are processed in DLGProc to respond to the action made by the user on the dialog. When processing the button action, create an IDD_ABOUTBOX using the Dialogbox function, specify its callback function to AboutProc, and process its corresponding message in the ABOUTPROC.

In EXE, we use implicit link to call DLL and use the showdlg function exported in the DLL to call dialogs in the DLL.

Using dialog box in Win32 DLL is as simple, let's take a look at how to use the dialog in the MFC DLL.

2. MFC DLL

Using dialogs in MFC DLL is not as simple as Win32 DLL, mainly because there is a problem with module status in the MFC program, that is, resource duplicate issues. (The term module here refers to a DLL (or a set of DLLs) of a DLL (or a set of DLL) that does not depend on the rest of the application but use the MFC run library. The MFC DLL we created is A typical example of this module.)

In each module (EXE or DLL), there is a global state data, and the MFC relies on this global state data to distinguish between different modules to perform the correct operation. This data includes: Windows universal handle (for loading resources), pointing to the pointer of the application current CWINAPP and CWINTHREAD object, OLE module reference count, and various mappings that maintain the Windows object handle and the corresponding MFC object instance Wait. However, when the application uses multiple modules, the status data of each module is not the scope of the application. Instead, each module has a private copy of the MFC status data. This global state data is called the MFC module state. The state data of the module is included in the structure and can always be used by a pointer to the structure. When the code enters a module when executed, only the status of this module is "current" or "valid" state, the MFC can correct this module and perform the correct operation.

For example, the MFC application can load strings from the resource file using the following code:

CString Str;

Str.LoadString (IDS_MYSTRING);

It is very convenient to use this code, but it masks the fact that Ids_MyString in this program may not be unique identifiers. A program can load multiple DLLs, some DLLs may also define a resource with the IDS_MYSTRING identifier. How do MFC know which resource should I load? The MFC uses the current module status to find the resource handle. If the current module is not the correct module we want to use, it will generate incorrect calls or errors.

According to the Link method of the MFC library, a MFC DLL has two ways to use the MFC library: static links to the MFC DLL and dynamic links to the MFC DLL. Below we will introduce how to switch the current module status in the correct way to use resources in the MFC DLL in accordance with these two types of MFC DLL.

1, static link to the MFC DLL

Static links to the rule DLL of the MFC and the MFC library static link, then the MFC library cannot be shared, so the MFC always uses the module status of the DLL it linked. This does not have problems with the status of the management module. However, the disadvantage of using this method is that the DLL program will become large, and repeated code will be left in the program. The example given below verifies this. This example can be done in accordance with the following steps:

1) In the VC menu.

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 dllstatic.cpp:

void showdlg ()

{

CDIALOG DLG (IDD_ABOUTBOX);

Dlg.domodal ();

}

4) Add a line in the Exports statement in the dllstatic.def file to export the ShowDLG function.

5) Compile DllStatic.dll and DllStatic.lib.

Continue to use the USE project in the previous section to copy the previously generated dllstatic.dll and dllstatic.lib to the project's debug directory, and will

EXTERN "C" __Declspec (dllexport) void showdlg ();

#pragma comment (Lib, "Debug / UseDLG")

These two rows are changed to:

Void showdlg ();

#pragma comment (lib, "debug / dllstatic") compiles and runs Use.exe. Click the button to see the modal dialog box in DllStatic pops up.

In this case, you can notice that the About dialog resource defined in the DLL is identical to the About dialog resource ID defined in the exe, but when we click on the button above Use.exe, the modality of the DLL is Dialog. Note When using a static link to the rule DLL of the MFC, there is no problem with the status of the management module.

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)

The macro is used to set PModuleState (pointing to the AFX_Module_state structure of the module global data is the module state) to the current instant effect space (the Remainder of the Immediate Containing Scope). 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.

Reposted:

http://www.vczx.com/Article/show.php?id=201

转载请注明原文地址:https://www.9cbs.com/read-88618.html

New Post(0)