From AFX

xiaoxiao2021-03-06  17

When you write the DLL of the MFC before, you will always see the prompt in the automatically generated code framework, you need to add AFX_Manage_State (AfxGetStaticModuleState ()) in each output function. I have never understood the meaning of this, and I have never done this, and the code has also works well, so I feel like a nonsense.

In the most recent project, you need to use the MFC generated interface in the DLL, and this finds that once the resource is placed in different dynamic libraries, and when it is still mixed with the multi-thread, things become abnormal, before the MFC I have been insufficient and cis. The inexplicable collapse of the program, inexplicable Assert, how resources are not loaded, why? Each time, I always try it. At the beginning of each thread, add AFX_Manage_State (AfxGetStaticModuleState ()) or one of the AFXSetResourceHandler (), and then solve it, but not very clear how is it? Winning, I always feel that this solution is very unheatched, as if the next second problem will suddenly take it.

The day before yesterday, this problem finally gotten to the ultimate, I spent several hours, how to try it, there is such a thing in the critical time, let me secretly swear, no more MFC. Just like a lot of movie plots, things finally got solved, this time I decided not to be so much longer, be sure to understand this matter clearly.

Here, what I encountered is, how to make the interface code in the DLL use the DLL resource (resource), how to load a dialog box with IE controls in the working thread?

I asked my colleagues, how did they implement DLL resource switching? AFX_MANAGE_STATE (AFXGETSTAICMODULESTATE ()) This is their answer, as Microsoft's recommendation, it is so simple! Let's take a look, what did this code do?

#define AFX_MANAGE_STATE (P) AFX_MAINTAIN_STATE2 _CTLSTATE (P);

AFX_MAINTAIN_STATE2 :: AFX_MAINTAIN_STATE2 (AFX_MODULE_STATE * PNEWSTATE)

{

m_pthreadstate = _afxthreadState;

m_pprevmodulestate = m_pthreadstate-> m_pmodulestate;

M_PthreadState-> m_pmodulestate = pnewstate;

}

_AFXWIN_INLINE AFX_MAINTAIN_STATE2 :: ~ AFX_MAINTAIN_STATE2 ()

{M_pthreadstate-> m_pmodules = m_pprevmodulestate;}

It turns out that it is to define a partial object that uses its constructor and the destructuring function to switch the STATE state in the port of the function, the exit of the function, I guess AFXGetStaticModuleState () must be the State of the current code where the current code is located.

Sure enough, please see

Static _AFX_DLL_MODULE_STATE AFXMODULESTATE

AFX_MODULE_STATE * AFXAPI AFXGETSTATICModuleState ()

{

AFX_MODULE_STATE * PModuleState = & AFXModuleState;

Return PModuleState;

Class _afx_dll_module_state: public AFX_MODULE_STATE

// AFX_MODULE_STATE (Global Data for a Module)

Class AFX_MODULE_STATE: PUBLIC CNOTRACKOBJECT

{

...

CWINAPP * M_PCURRENTWINAPP;

Hinstance M_HcurrentInstanceHandle;

Hinstance M_HcurrentResourceHandle;

LPCTSTR M_LPSZCURRENTAPPNAME;

Byte M_Bdll; // True IF Module Is A DLL, False IT IT IS AN EXE

...

CoCCManager * m_poccmanager;

...

It has to be said that MFC puts a lot of data, it is very complicated, and structural is very poor.

}

AfxModuleState is a static member of the DLL, naturally can be accessed by code in the same DLL, but when is initialized?

EXTERN "C"

Bool WinApi Dllmain (Hinstance Hinstance, DWORD DWREASON, LPVOID / * LPRESERVED * /)

{

...

Afxwininit (Hinstance, NULL, _T ("), 0);

...

}

Bool Afxapi AfxWininit (Hinstance Hinstance, Hinstance Hprevinstance,

LPTSTR LPCMDLINE, INT NCMDSHOW)

{

Assert (hprevinstance == null);

// Handle Critical Errors and Avoid Windows Message Boxes

SetErrorMode (setErrorMode (0) |

SEM_FAILCRILEERRRORS | SEM_NOOPENFILEERRORBOX;

// set Resource Handles

AFX_MODULE_STATE * PModuleState = AFXGETMODULESTATE ();

PModuleState-> m_hcurrentinstancehandle = hinstance;

PModuleState-> M_HcurrentResourceHandle = Hinstance;

...

}

This structure is initialized with the Hinstance of the DLL of the DLL.

At this time, we still don't understand why resource switching? What is the _afxthreadstate in front _AFXTHREADSTATE? It seems to have a relationship with thread, what is it?

Thread_local (_AFX_THREAD_STATE, _AFXTHREADSTATE)

#define thread_local (Class_name, Ident_name) /

AFX_DATADEF CTHREADLOCAL Ident_name;

Template

Class Cthreadlocal: Public CthreadlocalObject

Track again, find that in fact, the results, the basic function is to access the private data of the thread of the current row code. The so-called wire private data, that is, different threads perform the same piece of code, and the data obtained may be different. This remembers, many of the MFCs, are saved in the global map, and put on the private data area of ​​the thread, so transit the MFC object across threads is unsafe. However, why do MFC do this? This problem, I still don't understand so far. Still return to the beginning of the code, how is the resource switching?

Int cDialog :: Domodal ()

{

...

Hinstance hinst = afxgetresourcehandle ();

IF (M_LpszTemplatename! = null)

{

Hinst = afxfindresourceHandle (M_LpszTemplatename, RT_DIALOG);

HRSRC HRESOURCE = :: FindResource (hinst, m_lpsztemplatename, rt_dialog);

HDialogTemplate = loading (hinst, hresource);

...

}

_AFXWIN_INLINE HINSTANCE AFXAPI AFXGETRESOURCEHANDLE ()

{Assert (AfxCurrentResourceHandle! = Null);

Return AfxcurrentResourceHandle;

#define afxcurrentResourceHandle AfxGetModuleState () -> M_HcurrentResourceHandle

AFX_MODULE_STATE * AFXAPI AFXGETModuleState ()

{

_Afx_thread_state * pstate = _afxthreadState;

AFX_MODULE_STATE * PRESULT;

IF (PState-> m_pmodulestate! = null)

{

// Thread State's Module State Serves As Override

PRESULT = PState-> m_pmodulestate;

}

Else

{

// OtherWise, Use global app stat

PRESULT = _AFXBaseModuleState.getData ();

}

Assert (PRESULT! = NULL);

Return PRESULT;

}

The original MFC dialog box load resource is to load resources by getting a resourceHandler saved by ModuLestate corresponding to the current thread. So, the code in the DLL needs to be in the entry of the function, first replace the moduleState of the currently executive thread to the DLL's State, which can load the DLL resources! At this time, I suddenly understood, why do you need to rely on the private data of the thread to save Modules, in fact, it is to pass! - This is actually because cdialog is stored in another DLL, such as MFC40.DLL, if the MFC library is connected in sharing mode. The child of CDIALOG you wrote by the user does not place in the same DLL of CDIALOG, how do they pass this resource handle? Two solutions: 1, use parameters. 2, stored in a public place. The former needs to increase parameters, it is very troublesome, Win32 API seems to be this? The latter needs to determine where this public is? This makes people think of, build a public dynamic library? Is the main program? Many said more, J2EE has a container concept (COM seems to have, I don't know how .NET is), the components are survived in the container, and we can make this data in the container. In any case, the implementation of the MFC is to put on the private data area of ​​the thread, no public dynamic library, no need to trouble the main program, it will get it! It self-righteous solutions, perfect, causing our series of issues, especially those who don't understand. Regarding resource loading, the problem seems to have been solved, but there is a little bit of trouble is that the DLL I implemented is not output with ordinary output functions, but the output class, I don't want to add in the member function of each class. AFX_MANAGE_STATE (AFXGETSTACModuLestate ()). How to do it? Since the principle of resource switching has been known, we add two output functions, corresponding to the construction and destructive function of AFX_MAINTAIN_STATE2, and call before and after the class is used. Alternatively, put it in the construction of the class and the destructor. Alternatively, it is declared as a member variable. In any case, it is necessary to ensure that the resource switching should be correctly nested, and it is not integrated - this situation occurs when crossing between different DLLs.

Ok, now the resources in the DLL can be called correctly, but when we contain IE controls, we have failed, why? I know that Dialog needs to do some special processes for ActiveX controls, and I also know, I also know that Coinitialize (), but I have never thought of needing two together to make IE, but finally That's it. Surprisingly, if not in the working thread, do not need coinitialize (), you can load the IE control, this is no matter what it is.

Process_local (CoccuCManager)

Void AFX_CDECL AFXENABLECONTROLCONTAINER (CoccuCManager * Poccifer)

{

IF (Poccator == Null)

AfxoccManager = _afxoccmanager.getdata (); else

AfxoccManager = Poccator;

}

#define afxoccmanager AFXGETModuLestate () -> M_PoccManager

In this way, this _afxoccmanager should be the entire process, only one of the processes, just in that defined it. However, you need to pass the object (or create a custom) to ModuleState (Note that the previous AFX_Module_State contains this property), that is, if you want AFXENABLECONTROLCONTAINER (), such a specific ModuLestate has an Occmanager information. ! However, please note that after you have changed the resources correctly in the target DLL, you can do it, as follows:

AFX_MANAGE_STATE (AFXGETSTATICModuleState ());

Coinitialize (NULL);

AFXENABLECONTROLCONTAINER ();

At this point, this problem, I have finally been clarified in the context.

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

New Post(0)