When you use an MFC resource in a DLL project, the form cannot be displayed. How can this problem be solved? (The content of this article is reprinted and not understood by readers)

Source: Internet
Author: User

Afx_manage_state (afxgetstaticmodulestate (); // this parameter is used for status protection during module switching,

1. afxgetstaticmodulestate () points to the current module status;

2. The status of the original module is automatically restored after the current function call ends;

3. It is used to switch the module status when the MFC functions, classes, and resources are called in the DLL.

I encountered a problem when calling domodal In the DLL dialog box yesterday. The error is afxwin1.inl's 22 rows. It is strange that this problem occurs when the program adds a function. I still don't understand why the program code hasn't changed, or why it hasn't appeared now. I just added a function.

I really don't like to change it back. It's hard to delete the code that I can easily add. In addition, I always think that the added code will not cause such a problem and I will go online, I searched for it and found it.

Said ah, just add this statement before domodal. Afx_manage_state (afxgetstaticmodulestate ());

So I searched some related stuff to see what this stuff was. That's it.

Well, find another one.

From msdn:

By default, MFC uses the resource handle of the main application to load the resource template. if you have an exported function in a DLL, such as one that launches a dialog box in the DLL, this template is actually stored in the DLL module. you need to switch the module state for the correct handle to be used. you can do this by adding the following code to the beginning of the function:

Afx_manage_state (afxgetstaticmodulestate ());

This swaps the current module state with the state returned from afxgetstaticmodulestate until the end of the current scope.
That is to say, not every DLL's output function needs to be called before it can be used only when the source resource is used, such as when a conversation box is to be called!

DLL resources are shared. This function is used to prevent errors caused by resource modification by different processes!

By default, MFC uses the resource handle of the main application to load the resource template. The resource template in dll exists in the DLL template, therefore, you must use this statement to switch to the correct module status returned by afxgetstaticmodulestate to obtain the correct handle.

 

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/spritelw/archive/2006/07/16/928499.aspx

 

(Convert) afx_manage_state (afxgetstaticmodulestate ()
Www.diybl.com time: Author: anonymous name Edit: This site click: 1034 [comment]

Recently, I wrote a program to create a framewnd In the DLL. After a week, I found that I had to add less than one statement.
Afx_manage_state (afxgetstaticmodulestate (), now records the technical documents transferred from the Internet and forgets them.
(Convert) afx_manage_state (afxgetstaticmodulestate ())

When I used to write the mfc dll, I always saw a prompt in the automatically generated code framework. I need to add afx_manage_state (afxgetstaticmodulestate () to each output function ()). I have never understood the meaning of this, nor have I done so, and the code works well, so it seems like a waste of words.

In a recent project, you need to use MFC In the DLL to generate an interface. This means that once resources are placed in different dynamic libraries and mixed with multiple threads, things become abnormal and complex, and the previous knowledge of MFC has been insufficient and cannot cope with it. The program unexpectedly crashes, the inexplicable assert, and the resources cannot be loaded. Why? Every time, I always try to add afx_manage_state (afxgetstaticmodulestate () at the beginning of each thread, or use afxsetresourcehandler () in some places, and then the problem is solved, but I don't quite understand what is going on. I always feel this solution is quite uncomfortable, as if the problem will suddenly emerge in the next second.

The day before yesterday, this problem was finally solved to the extreme. It took me several hours to try and it was impossible to succeed, I swear that I will never use MFC again. Just like many movies, things have finally been solved. This time I decided not to forget it. I must understand it clearly.

Here, I encountered a problem: how to make the interface code in the DLL use the DLL resource, and how to load the dialog box with the IE control in the working thread?

I asked my colleagues how they switched DLL resources? Afx_manage_state (afxgetstaticmodulestate () is their answer. It is as simple as Microsoft's recommendation! Let's take a look at what the code has done?

# 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_pmodulestate = m_pprevmodulestate ;}

Originally, it was to define a local object and use its constructor and destructor to switch the state at the function entry and exit. I guess afxgetstaticmodulestate () obtain the DLL state of the current Code.

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 if it is an EXE

...
Coccmanager * m_poccmanager;
...

We have to say that MFC has piled up a lot of data here, which is very complicated and has a very bad structure.
}

Afxmodulestate is a static member of the DLL. It can naturally be accessed by the code in the same DLL, but when will it be initialized?

Extern "C"
Bool winapi dllmain (hinstance, DWORD dwreason, lpvoid/* lpreserved */)
{
...

Afxwininit (hinstance, null, _ T (""), 0 );
...
}

Bool afxapi afxwininit (hinstance, hinstance hprevinstance,
Lptstr lpcmdline, int ncmdshow)
{
Assert (hprevinstance = NULL );

// Handle critical errors and avoid windows message boxes
Seterrormode (0) |
Sem_failcriticalerrors | sem_noopenfileerrorbox );

// Set resource handles
Afx_module_state * pmodulestate = afxgetmodulestate ();
Pmodulestate-> m_hcurrentinstancehandle = hinstance;
Pmodulestate-> m_hcurrentresourcehandle = hinstance;

...

}

Originally in the DLL entry function, this structure was initialized with the DLL's hinstance.

At this time, we still do not understand, why do we need to switch resources? What is the _ afxthreadstate that we started earlier? It seems to be related to thread. What is it?

Thread_local (_ afx_thread_state, _ afxthreadstate)

# Define thread_local (class_name, ident_name )/
Afx_datadef cthreadlocal <class_name> ident_name;

Template <class type>
Class cthreadlocal: Public cthreadlocalobject

Next, we track down and find that the code is becoming increasingly difficult to understand, but the basic function is to access the private data of the thread of the current code line. The so-called private data of a thread means that different threads may execute the same code segment to obtain different data. This reminds me that many of the handles of MFC are stored in the Global Map and placed in the private data zone of the thread. Therefore, it is unsafe to transmit the MFC object across threads. But why does MFC do this? So far, I still cannot understand this problem.

Or back to the initial code, how is resource switching done?

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 = loadresource (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 state
Presult = _ afxbasemodulestate. getdata ();
}
Assert (presult! = NULL );
Return presult;
}

In the original MFC dialog box, resources are loaded by obtaining the resourcehandler saved by the modulestate corresponding to the current thread. Therefore, the code in the DLL must first Replace the modulestate of the current execution thread with the state of the DLL at the function entry to load the DLL resources! At this time, I suddenly understood why we need to rely on the private data of the thread to save the modulestate. In fact, it is actually a transfer! -- This is because the cdialog is stored in another DLL, such as mfc40.dll. If you connect to the MFC library in the shared mode. The cdialog subclass compiled by the user is not placed in the same DLL of cdialog. How do they transmit this resource handle? Two solutions: 1. Use parameters for transmission. 2. It is stored in a public place. The former needs to add parameters, which is very troublesome. Does the Win32 API seem to be implemented in this way? The latter, You need to determine where this public place is located? This reminds us of the creation of a Public dynamic library? Provided by the main program? To put it another way, there is a container concept in J2EE (COM + seems to have one, but I don't know.. Net), the components are all stored in the container. At this time, we can imagine storing the data in the container. In any case, the implementation of MFC is placed in the private data zone of the thread. It does not need public dynamic libraries or master programs! It thinks that a good solution is perfect, but it triggers a series of problems, especially those who do not understand it.

It seems that the problem has been solved when it comes to resource loading, but there is a little bit of trouble that the dll I implemented is not output by a common output function, but by an output class, I don't want to add afx_manage_state (afxgetstaticmodulestate () to the member functions of every class ()). What should we do? Now that we know the principle of resource switching, we add two output functions, which correspond to the construction and destructor of afx_maintain_state2 respectively. We can call them before and after class usage. Or, they are placed in the class constructor and destructor respectively. Or, it is declared as a member variable. In any case, you need to ensure that resource switching must be correctly nested and cannot be cross-called across different DLL files.

Now the resources in the DLL can be called correctly, but when the dialog contains the IE control, we still fail. Why? I know that for ActiveX controls, dialog requires some special processing, afxenablecontrolcontainer (). I also know that to use Com, coinitialize () is required (), however, I never thought that I could get ie out only when I used it together, but in the end it was like this. The strange thing is that if coinitialize () is not required in the working thread, the IE control can be loaded.

Process_local (coccmanager, _ afxoccmanager)

Void afx_cdecl afxenablecontrolcontainer (coccmanager * poccmanager)
{
If (poccmanager = NULL)
Afxoccmanager = _ afxoccmanager. getdata ();
Else
Afxoccmanager = poccmanager;
}

# Define afxoccmanager afxgetmodulestate ()-> m_poccmanager

In this case, the _ afxoccmanager should belong to the entire process, and there is only one process, that is, the DLL that defines it. However, you need to pass this object (or create a custom one) to modulestate (note that this attribute is included in the afx_module_state), that is, afxenablecontrolcontainer, in this way, the specific modulestate has the occmanager information! However, please note that you must switch the resource correctly in the target DLL before proceeding, as shown below:

Afx_manage_state (afxgetstaticmodulestate ());
Coinitialize (null );
Afxenablecontrolcontainer ();
 

Article Source: DIY tribe (http://www.diybl.com/course/4_webprogram/asp.net/asp_netshl/20071211/91494.html)

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.