Is there any class count limit in MFC project compiled with /CLR

2

With the risk to fall into too specific question...

Given a C++ MFC (mixed, not shaked) project compiled with /CLR, I have 200 classes already defined.

When I add a new empty class to this project, an error raises when I compile and execute in debug mode.

An unhandled exception of type 'System.IO.FileLoadException' occurred in Unknown Module.

Additional information: Could not load file or assembly 'ProjectA, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Could not find or load a type. (Exception from HRESULT: 0x80131522)

ProjectA is the name of the MFC project itself. There is no reference to any ProjectA assembly on project configuration, and there is no reference to another custom assembly.

This project only have references to some .NET Framework assemblies, in order to allow that some of custom defined classes in the project can use CLR classes.

Then, the question is...

  • Do you know whether there is any limitation of class number on a MFC C++ project?

EDIT:

As I say in comments, in release mode the compilation succeed without errors.

Also, I clean, build, clean, close Visual Studio, reboot computer... and the problem still appears. If I keep in 200 classes, there is no error. When I go to 201, the error appears.

Currently I'm trying to reproduce in a new default MFC project, adding classes till arrive to 200, to confirm that there is a real limitation.

EDIT 2: ERROR FIXED

Great. @MSX and @frymode show me how avoid the error with his comments.

In the Visual Studio development environment (source / source):

  1. Open the project's Property Pages dialog box.
  2. Click the C/C++ folder.
  3. Click the Code Generation property page.
  4. Modify the Enable String Pooling (/GF) property.

Thank you guys!

debugging
visual-studio-2013
mfc
c++-cli
clr
asked on Stack Overflow Oct 30, 2014 by HuorSwords • edited May 23, 2017 by Community

2 Answers

5

The /GF hack is a known workaround for this problem. It is however not a correct one, you are putting a band-aid on a heavily bleeding wound. Pretty important that you heal the problem instead of putting a patch on it, this heavily affects the way your program runs at runtime as well.

The problem maker is the <Module> class, an internal class that the C++/CLI compiler generates. You can see it with ildasm.exe or a good decompiler. This class is required as a home for declarations in your program that are not class members, valid in native C++ but not supported by the CLR. Which demands that every variable or function declaration is a member of a class. The C++/CLI compiler solves it by moving such a declaration into the <Module> class.

There is however a limit on the number of members in a class, they are represented in the metadata of the .NET assembly with a metadata token. An index into other tables. The upper byte identifies the table number, the lower bytes are the index in the table.

You exceeded that limit. This is bad.

A problem with the /clr compile option is that it works too well. It is capable of compiling any C++03 compliant native C++ code to MSIL. Such code will be just-in-time compiled to machine code by the jitter, just like normal managed code. It is however not verifiable code and it doesn't act like managed code at all, you can blow up your program with pointer fumbles just as easily. And above all, it is not code that's optimized with the native C++ back-end. Only the jitter optimizer has a shot at improving that code, it cannot do nearly the quality job that the native C++ optimizer can do, given that it runs with a hard upper limit on how much time it can spend on doing that job.

Have a look-see with a decompiler to see what ended up in that <Module> class. That's going to be overwheliming at first, you know you've got a big one right now. You fix this problem by spending more time segregating the code into the managed parts and the native parts. Where the native code should be compiled without /clr in effect. It is a per-source file setting, you can even switch back-and-forth in a single source code file with #pragma managed. The simplest way to segregate is by keeping your native code in its own library or DLL.

answered on Stack Overflow Oct 30, 2014 by Hans Passant
2

This link shows that there's no limit to the number of types you can have in a namespace (not a project). Considering, that a namespace can be split across different assemblies, you could, at least in theory, have an unlimited number of types. However, this post affirms that the maximum number of classes in a .DLL is 16777215. Probably, you'll run out of memory before you reach that number of classes :)

Just for information: there seems to be a limit to the number of fields per class, though.

P.S.: Here's the solution to your problem taken from this link

  1. Open the project's Property Pages dialog box.
  2. Click the C/C++ folder.
  3. Click the Code Generation property page.
  4. Modify the Enable String Pooling property.
answered on Stack Overflow Oct 30, 2014 by MSX • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0