menu

Questions & Answers

Windows C++ MFC migration: why does win32u.dll load before mfc140d.dll in some cases?

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 and I'm 95% sure this is due to duplicate CWinApp instances. My recollection is that when Migrating MFC to Win10, one must take care in the order of *.h includes which has been done... but I think there is a similar problem here.

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.

enter image description here

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

Comments:
2023-01-17 00:49:23
"I will include some links to relevant StackOverflow questions that are similar in my search for an answer to this question." Just checking- are those pending? I don't see them.
2023-01-17 00:49:23
The code is loading the debug MFC DLL and the release Runtime Support DLL. This looks suspicious.
2023-01-17 00:49:23
Richard, That is key. It is a Debug build (or supposed to be) and is possibly linking to a release build of lib4cxx (Apache Logger code). The deployment/control of that library is questionable... so could be getting a release build of that which is somehow triggering release runtime inclusion.
2023-01-17 00:49:23
I don't think MS has ever supported mixing matching debug and release builds in the same program. ABI compatibility and multiple Heaps. Try running Dependency Walker over each component starting with the exe.
2023-01-17 00:49:23
I don't think MS has ever supported mixing matching debug and release builds in the same program. ABI compatibility and multiple Heaps. I would expect UB from mixing the 2 with any version of msvc.
2023-01-17 00:49:23
@RichardCritten, mixing debug and release builds is bad practice, but it is supported. Ross Youngblood already mentioned it works on most machines.
2023-01-17 00:49:23
It's not just that mixing debug and release configurations of support libraries isn't supported. It's not even supported to have any more than one copy of the support libraries in any given process. If it "works" it doesn't do so by virtue of being correct. It works because it hasn't failed yet.
2023-01-17 00:49:23
What is not clear from Richard's post is which library is coming from a release build? Is win32u.dll supposed to be win32uD.dll? I need to check that. Clearly Release and Debug builds are incompatible. What is not clear to me is which copy of the support libraries is the duplicate. I'm assuming at the moment it is win32u.dll. I need a resource that identifies the DLL's for various support libraries to make sense of this and track down what *.h file or component is triggering the unwanted support library inclusion in the code.
2023-01-17 00:49:23
How does the new system differ from the old system? Problems might be caused by them. And does this issue occur before using Apache log4cxx?
2023-01-17 00:49:23
You can enable loader snaps and run the application under a debugger. That'll show you detailed information for module loading and unloading.
2023-01-17 00:49:23
Thanks for the loader snaps link. That is good reading. I will add that link. The original txt diff post is from the "loading DLL" messages Visual Studio 2019 displays in the output pane during initial exe launch. I guess what I'm searching for are what can change the DLL load order of implicitly loaded DLL's.
2023-01-17 00:49:23
Yujian, The crash is occuring during the "SHOW WINDOW" phase of startup. If the ASSERT failures are ignored, the application appears to work fine. There are 2 ASSERTS.
Answers(1) :

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.

Comments:
2023-01-17 00:49:23
So, are you saying that if the DLL LOAD order can change based on the %PATH%? I don't think this is the case. If I need to load the following DLL's A.dll, B.dll, and C.dll and expect them to load in the order A.dll, B.dll,C.dll. And that these Dll's are normally located at C:\foo[ABC].dll that I can change the load order? So placing C.dll in "." relative to the EXE, which is searched first will make it load first? I would need to test this, but don't believe it to be true.