1. Problem IntroductionWhen creating a DLL using MFC, The vs wizard automatically adds a class inherited from cwinapp, and reloads the initinstance and exitinstance functions. There is also a comment before this file: // todo: If this DLL is dynamically linked to the mfc dll, // Add the afx_manage_state macro to the very beginning of the function in any call/mfc function exported from this DLL. /// For example: // extern "C" bool Pascal export exportedfunction () // {// afx_manage_state (afxgetstaticmodulestate ()); //// this is the normal function body //} /// this macro is very important in every function before any MFC call. This means that // must appear as the first statement in the function, or even declare it before all object variables. // This is because their constructors may generate MFC // DLL calls. // Then, afx_manage_state (afxgetstaticmodulestate (); why is it very important to appear in every function?
2 Problem ResearchWe know that in the MFC code, if you want to access resources or information in some modules, you usually need to use the afxgetmodulestate function to obtain the pointer of the module information, then, how does MFC know the resources in the user's extended DLL? Let's take a look at the implementation of afxgetmodulestate: process_local (_ success, _ afxbasemodulestate) implements * afxgetmodulestate () {_ afx_thread_state * pstate = _ afxthreadstate; then * presult; if! = NULL) {// thread state's module State serves as override presult = pstate-> m_pmodulestate;} else {// otherwise, use global app state presult = _ afxbasemodulestate. getdata ();} assert (presult! = NULL); Return presult;} we can see from here that if we do not modify the m_pmodulestate pointer in _ afx_thread_state, it will point to the global variable _ afxbasemodulestate In the mfc dll. However, when MFC is running, it sometimes has to access resources in the mfc dll, so we can only modify this pointer before each time we want to use resources of this module, after use, the pointer is restored. This is the work completed by the macro afx_manage_state. Let's take a look at what afxgetstaticmodulestate () has done. Lresult callback (hwnd, uint, wparam, lparam); Class _ afx_dll_module_state: Public afx_module_state {public: _ afx_dll_module_state (): afx_module_state (true, success, 7 ){}}; static _ afx_dll_module_state afxmodulestate; afx_module_state * afxgetstaticmodulestate () {afx_module_state * pmodulestate = & afxmodulestate; return pmodulestate;} further analysis shows afxgetstaticmodulestate () The number is statically linked to the DLL like the dllmain function, that is, each dll has an independent afxmodulestate. We know that afx_module_state stores the independent information of each module, such as the class information implemented in the module, the resources used during the module running, and so on. Based on this, we can guess that afx_manage_state is used to pass the pointer that stores DLL information to MFC. Check out: # define afx_manage_state (p) afx_maintain_state2 _ ctlstate (p); afx_module_state * afxsetmodulestate (afx_module_state * pnewstate) {_ afx_thread_state * pstate = _ afxthreadstate; afx_module_state * pprevstate = pstate-> m_pmodulestate; pstate-> m_pmodulestate = pnewstate; return pprevstate;} afx_maintain_state ::~ Running () {_ afx_thread_state * pstate = _ afxthreadstate; pstate-> m_pmodulestate = m_pprevmodulestate;} running: running (afx_module_state * pnewstate) {m_pthreadstate = _ afxthreadstate; m_pprevmodulestate = m_pthreadstate-> m_pmodulestate; m_pthreadstate-> m_pmodulestate = pnewstate;} the above Code shows that afx_manage_state can restore the original modulestate pointer when exiting the function.
3 advantage and disadvantage AnalysisThere is no doubt that using this method is very helpful for the module's independence. For example, it can ensure that resources in this module are preferentially used when reading or creating resources, do not worry about conflicts with resource IDs in other modules. However, the disadvantage is obvious. afx_manage_state must be used before each function in MFC is called, which is very troublesome and sometimes some difficult-to-find errors may occur. For example, when cimagelist is placed in your own class, when the class instance calls the destructor, The destructor of cimagelist also releases the resources (handles) it reads ), however, afx_manage_state is often not used at this time (because cimagelist is released after the Destructor call is complete). In this way, the ing between the imagelist handle and the cimagelist pointer cannot be correctly released, it may cause future risks.
4 Conclusion1. This type of DLL is used only when the self-written library is an extension of the MFC class library. Otherwise, you can use a common DLL. 2. If the extension DLL does not use independent resources, you do not need to use the DLL type of the MFC extension. 3. You can place the resources in this DLL in the EXE or other types of main programs to avoid using this type of DLL. 4. If you use a static link DLL library, no such problem occurs.