What is up with "The application failed to initialize properly (0xc0000142)" error?
You've probably seen this error before in Windows at one time or another. Somebody launched calc.exe and it failed to run. The error doesn't tell you much. It provides you an hex error and your only option is to terminate the application.
I first encountered this error over 20 years ago and unfortunately, it is still around today.
There are primarily 3 actions that can cause this error:
- Launching lots of applications
- Launching an application as a different user
- Launching an application to a different desktop
This can happen from the user's desktop (the user who logged on by entering their credentials) or from a Windows Service. Programmatically, you launch applications using the family of CreateProcess APIs (CreateProcessAsUser(), CreateProcessWithLogonW(), CreateProcessWithTokenW()). Another thing you have to look out for in the call is whether, a desktop was specified in the STARTUPINFO struture:
typedef struct _STARTUPINFO {
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
.......
} STARTUPINFO, *LPSTARTUPINFO;
I'll come back to this later.
You'll see the API will succeed but if you check the exit code of the launched process (with GetExitCodeProcess()), it will return 128 or ERROR_WAIT_NO_CHILDREN, "There are no child processes to wait for."
If you are wondering what the error 0xc0000142 means in the above Message Box, you can find the error in ntstatus.h. It is STATUS_DLL_INIT_FAILED or "{DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally."
If you debugged the launched process and reviewed why Windows wasn't loading the DLL, it makes perfect sense that there was no error with CreateProcess (or CreateProcessAsUser) and the error was seen in the exit code of the launched process. CreateProcess's responsiblity is to find the exe and provide it to the Windows Loader, if this succeeds then CreateProcess() was done at this point. If the process can't load the DLLs that are required for it to run, this isn't the responsibility of the loader but is a failure with the application itself.
Why is this happening because of these actions?
It comes down to Windows Stations & Desktops. Before moving on, if you are not familiar with these objects, I suggest you read the following BLOG posts:
https://blogs.msdn.com/b/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx
https://blogs.technet.com/b/askperf/archive/2007/07/24/sessions-desktops-and-windows-stations.aspx
You can also read up on them in MSDN:
There are 2 issues you have to consider with Window Stations & Desktops:
- Desktop Heap Exhaustion - There is a limited amount of desktop heap (memory).
- Desktop Heap Security - When moving between users or desktops from the calling process, you have to ensure that the launched process has he appropriate permissions to the targeted process.
Let's first start with desktop heap exhaustion. There have been a lot of Blog Posts and KB articles on this topic. I will let you review the following links but I'll mention the following:
- Services (Session 0) have smaller desktop heaps than the INTERACTIVE desktop.
- Desktop Heap has increased with x64 systems.
- Desktop Heaps are smaller in Remote Desktop Sessions
There used to be a nice utility, Desktop Heap Monitor Version 8.1 to determine the amount of heap being used on your system. The only issue is that it was only supported on Windows 2000 and Windows Server 2003.
https://www.microsoft.com/en-us/download/details.aspx?id=17782
The only way to do this now is through the Kernel Debugger or through indirect methods such as creating as many Window Stations & Desktops to determine how much space is left.
https://blogs.msdn.com/b/ntdebugging/archive/2013/02/27/debugging-a-debugger-to-debug-a-dump.aspx
Desktop Permissions is the other issue where you could encounter this error. I touched this topic indirectly (following this BLOG post, you shouldn't encounter this issue) on the Windows SDK Support BLOG. "How to launch processes INTERACTIVELY from a service" See the following:
Years ago, I wrote the following KB article on how to deal with the issue by directly modifying the permissions on the Window Station and Desktop Object
"User32.dll or Kernel32.dll fails to initialize"
https://support.microsoft.com/en-us/kb/184802
I wouldn't recommend using this method anymore.
Today, the INTERACTIVE desktop permissions are accessed using the technique implemented in CreateProcessWithLogonW(). I discussed this in the following BLOG post:
I would recommend doing this to avoid directly modifying the permissions on a Window Station and Desktop controlled by the system since the system could make changes and negate yours and cause your application to not have any more permissions.
I will continue more posts on this topic in the future.