AfxoleInit()的一个错误(oleinit.cpp第54行)的简要分析

时间:2021-08-21 08:46:47

 

因为要在vc中连接数据库,所以在CMyApp::InitInstance()中调用了AfxOleInit(),但是不想,程序在Debug模式刚开始启动的时候报错,调试得出错的断言为

 _AFX_THREAD_STATE* pState = AfxGetThreadState();
 ASSERT(!pState->m_bNeedTerm); // calling it twice?

也就是说,该函数可能被执行了两次,但是搜索整个工程并没有发现啊,于是吧AfxOleInit()前移到InitInstance的最前面,发现没有报错,不断调整,定位到ProcessShellCommand(cmdInfo)这个函数。在此之后pState->m_bNeedTerm被修改。查找这个函数的源代码,

BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
{
 BOOL bResult = TRUE;
 switch (rCmdInfo.m_nShellCommand)
 {
 case CCommandLineInfo::FileNew:
  if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
   OnFileNew();
  if (m_pMainWnd == NULL)
   bResult = FALSE;
  break;

  // If we’ve been asked to open a file, call OpenDocumentFile()

 case CCommandLineInfo::FileOpen:
  if (!OpenDocumentFile(rCmdInfo.m_strFileName))
   bResult = FALSE;
  break;

  // If the user wanted to print, hide our main window and
  // fire a message to ourselves to start the printing

………
}

在这里,会执行红色部分,由于我用了CHtmlView文档类,所以在新建时,会调用AfxOleInit(),才导致后面重复调用….呵呵

后来查查微软的文档,其中有:

Why Is MFC Being So ASSERTive?

Dear Dr. GUI,

I saw your article on using COM objects with smart pointers, and I have attempted to use them without success!

I have an MFC SDI application that is based on CHTMLView. I want to use smart pointers to wrap interfaces in the mshtml.tlb type library. Based on your article, I decided to use smart pointers because it looked easy:

#import <mshtml.tlb>

CMyAppView::LoadData()
{
AfxOleInit(); // Initialize the COM library

MSHTML::IHTMLDocument2Ptr pIDoc;
MSHTML::IHTMLElementCollectionPtr pICollection;

pIDoc = GetHtmlDocument();
pICollection = pIDoc->Getall();

//use the collection
int nLength = pICollection->length;
}

But when I run my app, it asserts on the AfxOleInit() call like this:

Debug Assertion Failed!

File: oleinit.cpp

Line: 54

Is there something I have missed in my code?

Regards,

Mark Reed

Dr. GUI replies:

Dr. GUI is flattered that you have taken his advice from previous columns. The good doctor still highly recommends using smart pointers! Unfortunately, the problem you are having with AfxOleInit() is preventing you from even experimenting with their use. So, the doctor has done a triage with his residents and has a diagnosis and a surgical repair that will help with future MFC debug assertions.

The good doctor is convinced that calling AfxOleInit() is necessary when using smart pointers in an MFC application. AfxOleInit() initializes the COM library and should only be called once, preferably at the beginning of your application.

Although it may look like a crash, this debug assertion is much better! Assertions proactively encourage good code health, because they warn you of coding errors that could lead to an actual crash or unexpected behavior. Even better, the condition that causes the assertion can lead directly to the cause of the problem in your code. It follows logically that the first step in your case is to look at the MFC source code (located in "./VC98/MFC/SRC"). Run your application in the Visual C++ debugger by pressing the F5 key. When you get the debug assertion error, click the Retry button to debug. This opens OleInit.cpp and takes you to the source of the assertion inside the AfxOleInit() function, which looks like this:

ASSERT(!pState->m_bNeedTerm);    // calling it twice?

See the comment? The source code is giving you a hint that this method may be asserting because you are calling AfxOleInit() more than once. But the good doctor went through every line of his code and he is only calling it in our method call. Press the ALT+7 keys to bring up the callstack window. It shows that this assertion does generate from your CMyAppView::LoadData function. How can we know if someone else calls AfxOleInit() before we do?

The trick is to surgically implant a breakpoint in the MFC source code at the very first line of AfxOleInit() (press F9 on that line) and start the application in the debugger again. When the breakpoint is hit, look at the top few lines of the callstack:

AfxOleInit()
COleControlSite::CreateControl(Â…)
Â…
CHtmlView::Create(Â…)

Now, it’s more obvious! Because your view class derives from CHtmlView rather than CView, the CHtmlView::Create() method needs to create a Web Browser control. But, of course, first it calls AfxOleInit() for you.

Phew! That was a lot of work to find out that we don’t need to call AfxOleInit() at all in an MFC application that uses CHtmlView. But hopefully this demonstrates the tremendous benefit in using both the MFC source code and the callstack window. Dr. GUI recommends applying the same techniques to any future debug assertion failures.

This is what the good doctor calls a neat surgery. Your healing time will be negligible.

该段内容大致与我遇到的问题相同。

但是,当我在其中一个对话框类内定义_ConnectionPtr类型成员变量的时候,因为MFC构造各种对话框类型在处理程序命令行参数之前,此时会报错,因为COM未初始化,在我的程序中比较简单,不使用成员变量也可以解决问题,因为局部变量在运行时创建…此时COM已经初始化。对于必须使用成员函数的情况,把AfxOleInit()调用放在ProcessShellCommand()前即可,而并非简单的“That was a lot of work to find out that we don’t need to call AfxOleInit() at all in an MFC application that uses CHtmlView.” 这也算是对microsoft的DR GUI的一点补充吧。一直有个疑问:不知道这个DR是博士,还是“医生”。