locked
MFC and C++/CLI performance RRS feed

  • Question

  • Hello all!  First post...

    We have a large legacy MFC GUI app.  We have separately developed a C# library of algorithms that we'd like to integrate in with this MFC app. 

    Initially I added a C++/CLI class to this app (which made the appropriate call), set only that class' CPP file to /clr (and the other requisite settings like turning off C++ exceptions etc).  When I run and attempt to call the C++/CLI class from an unmanaged class, it crashed somewhere deep inside the CLR. 

    I found a sample on the Internet where this is working; in the sample, /clr is set project-wide (in the MFC project) and "Framework and References" is used to reference the needed .NET assemblies.

    My question -- it seems very "scary" (sorry, can't think of a better word) to me to have to set the /clr flag project-wide for our legacy large MFC app. Is that actually required?  Or is there just something I am missing?  Shouldn't all of the MFC app be able to be compiled unmanaged, and then just the single C++/CLI file that calls out to my C# algorithm library need to be /clr? 

    If I *do* need to set /clr project-wide, what is the potential performance impact?  Does that mean that every class in my project is being compiled as MSIL?

    Thanks in advance,

    Mike Johnson

    Tuesday, June 15, 2010 1:50 PM

Answers

  • Many thanks!  OK, I played with this some more and got this working.  For other folks, here's what I did:

    1.  Mark just the one C++/CLI file with /clr (and the other requisite changes that VC enforces when you do that)

    2. Add references to my .NET class library dlls that I want to make calls against - this was in Common Properties->Framework and References.  What I found was that after I added the /clr flag to one or more of my CPP files, I had to shut down and then reload the solution; otherwise the ".NET" and "Browse" tabs wouldn't show up on the "Add Reference" dialog.

    3. On the Linker->Advanced page, set "CLR Thread Attribute" to "STA Threading Attribute."  This gets you past an error about changing COM threading attributes when calling AfxOleInit() in the MFC application startup.  (Apparently MFC apps require STA, and .NET by default initializes MTA?)

    That's pretty much it!  I am now able to execute calls against my .NET library from MFC!

    Thanks again for the help!!

     

     

    • Marked as answer by Yi Feng Li Monday, June 21, 2010 3:01 AM
    Tuesday, June 15, 2010 9:31 PM
  • Do NOT ever set /clr on the entire project. It will be a complete performance killer.

    Marking just that one cpp file with /clr should work. If it does crash, it may be due to some subtle bug somewhere, either in the C++/CLI wrapper or in the C# library.

    If time's short, then an easy way out may be an MFC extension DLL compiled with /clr that will do the reverse of the C++/CLI wrapper. The extension DLL will expose an unmanaged interface for the main MFC app to call. And internally, it will use C++/CLI to call into the C# library. This way you keep your main app unmanaged, and it's only the extension DLL that's mixed-mode.

    Another option (unrecommended due to various potential problems) is to use COM interop and directly access the C# library.


    http://blog.voidnish.com
    • Proposed as answer by ildjarn Tuesday, June 15, 2010 10:02 PM
    • Marked as answer by Yi Feng Li Monday, June 21, 2010 3:01 AM
    Tuesday, June 15, 2010 2:10 PM

All replies

  • Do NOT ever set /clr on the entire project. It will be a complete performance killer.

    Marking just that one cpp file with /clr should work. If it does crash, it may be due to some subtle bug somewhere, either in the C++/CLI wrapper or in the C# library.

    If time's short, then an easy way out may be an MFC extension DLL compiled with /clr that will do the reverse of the C++/CLI wrapper. The extension DLL will expose an unmanaged interface for the main MFC app to call. And internally, it will use C++/CLI to call into the C# library. This way you keep your main app unmanaged, and it's only the extension DLL that's mixed-mode.

    Another option (unrecommended due to various potential problems) is to use COM interop and directly access the C# library.


    http://blog.voidnish.com
    • Proposed as answer by ildjarn Tuesday, June 15, 2010 10:02 PM
    • Marked as answer by Yi Feng Li Monday, June 21, 2010 3:01 AM
    Tuesday, June 15, 2010 2:10 PM
  • Many thanks!  OK, I played with this some more and got this working.  For other folks, here's what I did:

    1.  Mark just the one C++/CLI file with /clr (and the other requisite changes that VC enforces when you do that)

    2. Add references to my .NET class library dlls that I want to make calls against - this was in Common Properties->Framework and References.  What I found was that after I added the /clr flag to one or more of my CPP files, I had to shut down and then reload the solution; otherwise the ".NET" and "Browse" tabs wouldn't show up on the "Add Reference" dialog.

    3. On the Linker->Advanced page, set "CLR Thread Attribute" to "STA Threading Attribute."  This gets you past an error about changing COM threading attributes when calling AfxOleInit() in the MFC application startup.  (Apparently MFC apps require STA, and .NET by default initializes MTA?)

    That's pretty much it!  I am now able to execute calls against my .NET library from MFC!

    Thanks again for the help!!

     

     

    • Marked as answer by Yi Feng Li Monday, June 21, 2010 3:01 AM
    Tuesday, June 15, 2010 9:31 PM
  • Hi Nish,

    I know I'm resurrecting a thread from 3 years ago, but can you explain why setting /clr on the project is a performance killer? It seems, for example, that as soon as a class accepts a .net object, a large chunk of the project must be compiled with /clr turned on. On some occasions, particularly with memory starved machines, we are indeed seeing huge performance problems.

    In this example, picture.h can take an .net image. Not only does picture.cpp need to be compiled with /clr, but so does everything that uses it. This can escalate very quickly.

    class CLASS_EXPORT Picture : public CObject

    {

    public:

    ...

        void SetPicture(gcroot<System::Drawing::Image^> image);

        void Draw(CDC* pDC, CRect rect);

    ...

    }

    Since we started experiencing performance issues, I've been paying closer attention to how to best mitigate them. But it is not very easy to find good guidelines on what works. Do you have any suggestions?

    Wednesday, October 2, 2013 3:32 PM