MFC and module status

Source: Internet
Author: User

What is the module status?
In each Microsoft Foundation Classes (MFC) module (exe, DLL), there is a "global" data, MFC relies on this global data to perform the correct operation. This type of global data is called the status of the MFC module.
For example, MFC applications often use the following code to load strings from resource files:

Cstring STR;

Str. loadstring (ids_mystring)

This code is very convenient, but it masks the fact that ids_mystring in this program may not be a unique identifier. A program can load multiple DLL files. Some DLL files may use the ids_mystring identifier to define a resource. How does MFC know which resource to load? MFC uses "Current module status" to find the resource handle.

The resource handle is not just a buffer for MFC global data. See the afx_module_state structure described in MFC/include/afxstat _. h to find the complete list.

When do I need to manage the module status?
When compiling a DLL using MFC, you can use MFC in three ways:
Static Link
Compile as dynamic link of extended DLL
Dynamic Links compiled as regular DLL
If the application and the MFC are statically linked, the MFC cannot be shared. In this way, the status of the management module does not exist. MFC knows how to load resources from static linked DLL. The disadvantage of using this method is that DLL (ARX) will become larger and duplicate code (for example, that of MFC's) will be left in the program ).
When an application is dynamically linked to MFC, for example, the loadstring function requires additional information to identify the correct resources. (MFC finds the call stack and determines the module handle to call the DLL. However, this is an unreliable solution because the compiler will optimize some calls when compiling the release version .)

MFC picks up the additional information from the current module status. The Application Program (exe, DLL) is responsible for correctly managing the current module status. In other words, when using dynamic links, MFC needs to know which module is operated correctly.

Differences between conventional DLL and extended DLL
When dynamically linking MFC into a so-called regular DLL you specify the _ usrdll Preprocessor directive to the Preprocessor.
When you dynamically link MFC to a conventional DLL, you must specify _ usrdll as a Preprocessor.

In MFC/include/afx. H, the pre-processor symbol is forcibly defined as a symbolic reference using the following statement:

# Ifdef _ usrdll

# Pragma comment (linker, "/include :__ afxforceusrdll ")

# Endif

This symbol is provided by MFC/src/dllmodul. cpp. Dllmodul. obj is a part of the static library mfcs42.lib. This static library is linked to all modules that use mfc42.dll (exe, DLL ).

Dllmodul. cpp is also declared as an instance of afx_module_state, which creates and allocates the module status for the conventional DLL.

When MFC is dynamically linked to the extended DLL, _ usrdll is not specified as a pre-processor. Therefore, dllmodul. OBJ does not have a symbolic reference, and there is no module status allocated for the extended DLL.

MFC stores the current module status in the thread local variables (see _ declspec (thread) in the Visual C ++ document. When the execution thread is switched between modules, the local variable of this thread is reset. This switch can be automatic (see the example in tn058 ). However, in ARX or DBX applications, you can only switch between them manually. (See the afxsetmodulestate function in MFC/src/afxstate. cpp)

In short, the difference between a conventional DLL and an extension DLL is that a conventional dll has its own module status, while an extension DLL does not have its own module status. The extension DLL operates through the EXE or the module status of the conventional DLL. For the differences, see:





Therefore, if you create a DLL (ARX) That is dynamically linked to the MFC, you must know the difference between the conventional DLL and the extended DLL and manage the module status of the MFC accordingly.

How to manage the module status?
You do not need to manage the module status for statically linked applications, because MFC always uses the module status of the DLL it is linked. Now let's check the two situations when the MFC dynamically links the DLL.
How does mfc42.dll know which module status (such as resource) to use? If the DLL does not tell the MFC module status, it will not know. Then, MFC continues to run and uses the current module status.

Extension DLL usually does not care about the status of the MFC module. They are designed as extension MFC with classes, and applications and conventional dll can use the instances defined in them. In this case, the object exists in the called module and Its Module status. They can run regardless of the current module status. However, in the AutoCAD environment, we will find this situation: you need to use extended DLL to manage the module status.

If a dll extension requires some private resources to perform the correct operation (for example, an error message is displayed), it overwrites the resource handle of the current module using the following API functions:

Afxsetresourcehandle () sets the current resource handle
Afxgetresourcehandle () returns the current resource handle
Before returning from the extended DLL, the preceding resource handle must be reset.
(Note: If an extended DLL is created and the resources or classes output by it can be used by other DLL or EXE modules, you also need to create an instance of the cdynlinklibrary object. This is an uncommon issue in developing ObjectARX applications. For more information, see tn033 In the MFC Document .)

Common DLL and exe modules have their own module statuses, and they are responsible for correctly managing these module statuses. MFC provides a series of API functions and help classes to complete these tasks:

Afxgetstaticmodulestate () to obtain the module status of the call module. It only returns the global variables in dllmodul. cpp, Which is statically linked to the module.
Afxgetappmodulestate () returns the module status of the EXE module in the process.
Afxgetmodulestate () returns the status of the current module.
Afxsetmodulestate () sets the current module status.
Afx_manage_state is a macro, which shows a simple encapsulation class. It stores the status of the previous module in the constructor to overwrite the status of the current module and restores the status of the previous module in the release program.
The conventional DLL and exe modules need to use afx_manage_state (afxgetstaticmodulestate () for each pointer that allows the execution program to enter the module ()). This includes explicitly outputting global and member functions as well as virtual overwrites (called recall in RX ).
How to use MFC in ARX applications
Unless the module status management of the ARX application is one of the following, ARX encounters special problems when using MFC:
Fiber architecture of AutoCAD 2000)
Multiple application modules (static, conventional DLL, and extended DLL) are loaded to the same process space at the same time.
Using the mfc api of AutoCAD
The AutoCAD API Using MFC is used during execution.
We will discuss these situations one by one.
Context Conversion

AutoCAD 2000 uses context ("Contexts") to implement the MDI environment. (For more information about the context, see the Microsoft platform SDK documentation .) Because the current module status of MFC is stored in a local variable of a thread, when AutoCAD switches from one context to another context in the same thread, make sure that both the module status and resource handle have been correctly switched.

This process is completely executed in AutoCAD 2000, so the ARX application does not need to do any work.

Multiple MFC application modules run simultaneously
Consider the following: we have two ARX applications. The first. ARX application is executed as the common DLL of MFC. The second ARX application is executed as the MFC extension DLL. When the second ARX application is started, a non-modal dialog box is displayed, showing the number of objects added to the database, it inserts a database reactor in the database to get the objectappended notification. The first ARX application executes a command to display the dialog box. In this dialog box, there is a button to create a straight line in the database.
Consider the following event process:

After the second application is loaded, it does not switch the switch module status, but sets the resource handle to the current. The non-modal dialog box is displayed correctly.
After the first application is loaded, the user calls the command used to display the modal dialog box.
The status of the current module of MFC is converted to the first application, and the resource handle of Application 1 is set to the current.
The dialog box is displayed correctly. You can click a button to create a line in the database.
The first. ARX program creates a line in the database and triggers the notification in turn.
The second. ARX program tries to update the non-modal dialog box after receiving the notification.
In this case, the MFC may be invalid, which is determined by the function to be executed in Application 2. The execution of simple setwindowtext () will not cause problems, but if you call the cobject: iskindof of the MFC class registered in the extension DLL, it will fail. In this case, the more common problem is that the extended DLL tries to access the mfc api of AutoCAD. This situation will be discussed in the next section.
The problem is that ARX applications designed to expand DLL normally assume that the current module status is AutoCAD. This is usually a security assumption, but sometimes it is not safe, such as in the case above. So what should we do?
AutoCAD should switch the module status to itself before the notification reaches the second application (step 6 above. However, if we study this problem further, we will find that it will not be possible. Because the objectdbx subsystem that changes and triggers notifications cannot understand MFC (it does not use MFC itself ).
Before executing any state-sensitive operation, the extension DLL should declare the hypothesis and confirm that the status of the AutoCAD module is set to current. Arx applications can call afx_manage_state (afxgetappmodulestate () to implement this function.
Currently, most available ARX applications (including the AutoCAD 2000 core program) cannot protect themselves as shown above. If a common dll appears in the Acad process, it will become invalid or run abnormally.
Mfc api of AutoCAD

There are some useful APIs in AutoCAD to directly output the MFC objects used by AutoCAD. For example, cwinapp * acedgetacadwinapp () outputs the MFC Application object used by AutoCAD. The member functions of these objects can be used safely only when the module status of AutoCAD is current. Therefore, if you use an MFC Dynamic Link, you can only use these Apis. It must be determined that the current module status is indeed the status of the AutoCAD module.

Note the situation described in section 3.1.2.

Note that this part is different from that described in section 3.1.4. These APIs directly output MFC objects, so that AutoCAD has no chance to encapsulate these member functions to provide proper module status management.

AutoCAD 2000 also provides two MFC extension DLL (adui. dll, acui. dll), which can be used if the ARX application and MFC are dynamically linked. Because these extension DLL files cannot be used as static libraries, they cannot be used in applications with static links to MFC.

Use AUTOCAD APIs of MFC during execution
Many AutoCAD APIs use MFC during execution. Because the Acad module has its own module status, it is necessary to provide proper module status management on all entry points.
Unfortunately, R14 does not manage the module status at all. R2000 tries to solve this problem and provides proper module status management in Acad. EXE, but there are still some problems. The most serious problem is that, if the status of the AutoCAD module is not current, using the acutprintf function will cause a crash.

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.