I have customer code written for Visual Studio 6.0 MFC which has a simple GUI and launches an EXE with arguments. This code was ported from VS6.0 to VS2019 about 2 years ago and works in a production environment on several systems. We now have a new system where the code fails to function… and I’m starting to dig.
The code is throwing exception in appcore.cpp line 196
It is crashing at AfxGetThread() now that I have been able to get VS2019 to find "appcore.cpp".
This is new information.. I will be searching on AfxGetThread next… so this question likely to be a duplicate now.
One difference I have detected is the order where the Visual Studio 2019 debuger loads symbols. I can’t say for certain that this is an indication of the actual DLL load order at runtime, but it appears to be. The screenshot below is the SYMBOL load order where a difference is detected between the working and non working instance of the application.
In the image below we have a Tortoise SVN Diff of two ASCII files. One is the DLL symbol load order on the left when the application works. The second is the DLL symbol load order on the right when the application fails to work. Line 7 is the divergance, where in the failig case the library win32u.dll is pulled in before mfc140d.dll.
The customer code uses some Apache log4cxx libraries which I need to investigate, but at this point in the load sequence I’m not 100% sure differences in those libraries or *.h files used at build time could influence the DLL loading order.
So this is the puzzle I’m looking at.
I will include some links to relevant StackOverflow questions that are similar in my search for an answer to this question.
Possibly Useful Links:
https://learn.microsoft.com/en-us/cpp/porting/porting-guide-mfc-scribble?view=msvc-170
2
Answers
In this case, the crash in appcore.cpp was due to the code having 2 CWinApp derived objects in the code. And the crash occurs at construction time.
The first hurdle is to get VisualStudio2019 to find appcore.cpp and be able to step into this code. I browsed to C:Program Files(x86)VisualStudio and searched for "appcore.cpp". This provided the trail of breadcrumbs to get Visual Studio2019 the correct path when it asked for the file.
In my case the path is:
C:Program Files (x86)Microsoft Visual Studio2019ProfessionalVCToolsMSVC14.29.30037atlmfcsrcappcore.cpp
The second hurdle was to put a breakpoint at the ASSERT point, as the FIRST time the program comes up, this ASSERT is OK. At least in my case... the first constructor of the CWinApp object succeeded. So in my case the offensive code which was unexpectadly constructing a CWinApp derived object ran first. Then the second iteration through the ASSERT would happen.
By placing a breakpoint at the ASSERT, you can re-launch and look at the stack trace of the successful object to determine if it's expected or not.
In my case there was a *.h fix required to get ancient Visual Studio 6.0 MFC code to build and link successfully. I don't have the exact secret, but it's essentially getting a *.h to specify the proper WIN_VER minimum windows version before afx.h is included. For the code that failed, an incorrect *.h was included that included the fix PLUS objects that derived CWinApp.
As near as I can tell, the reason this worked on some sites and not others was due to a regression in the code that was built on that particular system.
The other "strange" behavior was that on the system with the bad *.h include the DLL symbol load order was different. I was able to replicate this bad behavior on more than one system running the "bad" Exe code. Then I did the same on working *.exe code. The strange thing was that the "bad" exe had reasonably correct sources in the workspace. So there were source control issues leading to this belief that it worked on one node and not others. The runtime behavior I was able to catch matched obsolete code committed to source control.
The DLLs are searched in order in different locations: Standard Search Order for Desktop Applications
Most likely the DLLs on the failing machine are missing or they are in the wrong location, so Windows grabs something else.
Make sure all the dependencies are installed in the correct folders.