CAUSE
The root of the problem exists in how MFC is terminating DAO. MFC calls
AfxDaoTerm from the exit instance of CWinApp. This is fine for applications
but isn't a good thing to do for DLLs because ExitInstance() is called from
the DLL_PROCCESS_DETACH case. Use of OLE and specifically DAO should be
avoided in the ExitInstance() of a DLL.
Another problem with the MFC DAO code is that it stores the pointer to the
database engine on a global scope so that if one regular DLL that links to
MFC dynamically closes and calls AfxDaoTerm, it closes the database engine
for any other DLLs which use DAO and link dynamically to MFC.
The line 36 assertion is caused by the fact that an exception gets thrown
in AfxDaoTerm when trying to call Release() on the database engine. The
exception prohibits the setting of m_pDAOEngine pointer back to NULL.
Again, this problem occurs because MFC incorrectly calls DAO in
ExitInstance() of a DLL.
Here is the code in AfxDaoTerm():
// Clean up engine object if necessary
if (pDaoState->m_pDAODBEngine != NULL)
{
pDaoState->m_pDAODBEngine->Release();
pDaoState->m_pDAODBEngine = NULL;
}
You can see that if an exception occurs in Release(), the m_pDAODBEngine
pointer is not set to NULL. Thus, the assert on line 36 of Daocore.cpp will
occur:
ASSERT(m_pDAODBEngine == NULL);
An access violation can occur if you perform the following sequence:
- Dynamically load DLL1 and use MFC DAO classes.
- Dynamically load DLL2 and use MFC DAO classes.
- Close DAO objects and unload DLL1.
- Do something with DAO in DLL2.
This occurs because the DLL1 has already shut down the DAO components.
There may be other scenarios that can cause other access violations to
occur. For example, do not create global MFC DAO objects within a DLL. The
resolution section below doesn't address this problem because it is
something that should not be done.
REFERENCES
For more information about problems using DAO in DLLs, please refer to the
following articles in the Microsoft Knowledge Base:
149889
PRB: Assertion or Problems Using DAO in a DLL
152315
PRB: When to Call AfxDaoTerm() in an Automation Server