FIX: Assert on Olefact.cpp Line 52 with IMPLEMENT_DYNCREATE and IMPLEMENT_OLECREATE_EX (325141)



The information in this article applies to:

  • Microsoft Visual C++ .NET (2002)

This article was previously published under Q325141

SYMPTOMS

When using IMPLEMENT_DYNCREATE and IMPLEMENT_OLECREATE_EX, you receive the following error message:
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!

Program: c:\projects\debug\Repro.exe
File: olefact.cpp
Line: 52

For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
---------------------------
Abort Retry Ignore
---------------------------

CAUSE

The Visual C++ .NET compiler does not respect the order of declaration when __declspec(selectany) is used.

RESOLUTION

In the Stdafx.h header file of the project that consumes your Microsoft Foundation Classes (MFC) extension DLL, predefine an empty AFX_COMDAT symbol by pasting the following code before you include (#include) any other header files:
      #define AFX_COMDAT
				

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. This bug was corrected in Microsoft Visual C++ .NET (2003).

MORE INFORMATION

The problem is that IMPLEMENT_RUNTIMECLASS uses the symbol AFX_COMDAT, as shown in the following code:
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) 	AFX_COMDAT const CRuntimeClass class_name::class##class_name = {
				
AFX_COMDAT is expanded by the preprocessor to __declspec(selectany).

IMPLEMENT_OLECREATE_EX does not use __declspec(selectany) (or AFX_COMDAT).

Steps to Reproduce the Behavior

There are two ways to reproduce the behavior:
  • Method 1 demonstrates just the core issue.
  • Method 2 demonstrates the problem in an MFC context and demonstrates how to generate Debug Assertion Failure.

Method 1

#include <stdio.h>
int func(char c) {
	return printf("%c\n",c);
}
int a = func('a');
__declspec(selectany) int b = func('b');
int c = func('c');
int main () {
	return a+b;
}
// Expected result: a b c
// Actual result: a c b
				

Method 2 (in Visual C++ .NET)

  1. Create an MFC extension DLL:
    1. Use the MFC DLL template to create a new Visual Studio .NET project.
    2. On the Application Settings page of the wizard, under DLL type, click MFC extension DLL, and then click Finish to create the DLL.
  2. Work with the classes as follows:
    1. Create a new MFC class named CBase that is derived from CWnd:
      1. In ClassView, right-click the project, click Add, and then click Add Class.
      2. In the Add Class wizard, select the MFC Class template, click Open, type CBase in the Class name box, and then click Finish.
    2. Export (and then import) the whole class from the DLL by marking the class with the AFX_EXT_CLASS macro.
    3. Paste the following DECLARE_DYNAMIC macro anywhere in the base class (if it has not already been added by the code wizards):
    class AFX_EXT_CLASS CBase : public CWnd
    {
        DECLARE_DYNAMIC(CBase)
    ...
    }
    					
  3. Create a new MFC executable project to test the new extension DLL. This can be of type Win32 Console Project (with MFC support added), or it can be the standard MDI or SDI MFC applications.
  4. In the new MFC executable project, open the Stdafx.h file, go to the end of the file, and then paste in this reference to the header file:
         #include <afxctl.h>
    					
  5. In the MFC executable, create a class named CDerived that is derived from the CBase class (which is exported from the extension DLL):
    1. In ClassView, right-click the project, click Add, and then click Add Class.
    2. In the Add Class wizard, select the MFC Class template, and then click Open.
    3. Type CDerived in the Class name box, and then click Finish.
  6. Change the following as described:
    • Replace all references to CWnd in the new class with CBase.
    • In derived.h, change the base class for CDerived from CWnd to CBase.
    • In derived.cpp, change the IMPLEMENT_DYNAMIC and BEGIN_MESSAGE_MAP macros to use CDerived instead of CWnd.
  7. You must #include the header file for CBase: in derived.cpp, add #include base.h where base.h includes the path to the file Base.h.
  8. Link with the import library created for the extension DLL:
    1. In Solution Explorer, right-click the project, and then click Properties.
    2. In the left pane, expand the Linker folder, and then click Input.
    3. In the right pane, in the Additional Dependencies box, type myextdll.lib where myextdll.lib is the name (including the path) of the export library that is generated by the extension DLL project that you created earlier.
  9. In the CDerived class definition, replace the macro DECLARE_DYNAMIC call with the macro DECLARE_DYNCREATE, and then add the following macro call to DECLARE_OLECREATE_EX:
    class CDerived : public CBase
    {
        DECLARE_DYNCREATE(CDerived)
        DECLARE_OLECREATE_EX(CDerived);
    ...
    }
    					
  10. On the Tools menu, click Create GUID, use format 1 (IMPLEMENT_OLECREATE), and then fill in the Xs in the IMPLEMENT_OLECREATE_EX macro shown in the next step.
  11. In the implementation file for CDerived, replace IMPLEMENT_DYNAMIC with IMPLEMENT_DYNCREATE.
  12. In the implementation file for CDerived, paste the following code anywhere in global space:
    IMPLEMENT_OLECREATE_EX(CDerived, "Derived", xxxxxxxx, xxxx, xxxx, xx, xx, xx, xx, xx, xx, xx, xx);
    BOOL CDerived::CDerivedFactory::UpdateRegistry(BOOL) {return FALSE;}
    					
  13. Build the MFC extension DLL project, and then build the MFC executable project. Make sure that the DLL can be found from the executable file.
  14. Run the MFC executable. The Debug Assertion Failed error message occurs.

Modification Type:MajorLast Reviewed:4/11/2003
Keywords:kbfix kbbug kbCompiler kbpending KB325141