I've built an application with Visual Studio 2015 Community edition. When some of my users try to run it it they receive the following error:
The program can't start because api-ms-win-crt-runtime-l1-1-0.dll is missing from your computer. Try reinstalling the program to fix this problem.
Clearly this is solved by installing the Update for Universal C Runtime in Windows (KB2999226). I could check for the hotfix during the install script but all of the methods I've found to do this are either too slow or unreliable.
How can I prevent this error from occurring? Can I change my solution so that I don't require this dependency? Am I linking against something I can remove? Can I redistribute the hotfix along with my application?
Edit: In the project properties, the "Target Platform Version" is 8.1 and the "Platform Toolset" is "Visual Studio 2015 (v140)", if that helps at all.
Edit 2: I've tried copying all of the Universal C Runtime Library DLL's to the application directory since Microsoft now allows (but doesn't recommend) local mode installation of the UCRT. There are 41 files in C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64
and api-ms-win-crt-runtime-l1-1-0.dll
is one of them. However, now running the application results in this error:
The application was unable to start correctly (0xc0000142). Click OK to close the application.
I've tried debugging the application with MSVS 2015 but got nowhere. I opened the executable in Dependency Walker and it appears that I'm missing similar DLLs listed in this answer, which says that Dependency Walker is old and this is a red herring.
I tried running the application through Process Monitor (procmon) and there's nothing unusual. The application simply calls "Process Create" on WerFault.exe and then "Thread Exit."
Edit 3: I enabled loader snaps on the executable and got this when running it from cdb, if it helps:
...
00c0:1200 @ 02106250 - LdrpFindOrMapDependency - RETURN: Status: 0x00000000
00c0:1200 @ 02106250 - LdrpFindOrMapDependency - ENTER: DLL name: api-ms-win-core-sysinfo-l1-2-1.dll.
00c0:1200 @ 02106250 - LdrpFindOrMapDependency - INFO: DLL name api-ms-win-core-sysinfo-l1-2-1.dll was redirected to C:\WINDOWS\SYSTEM32\kernelbase.dll by SxS.
00c0:1200 @ 02106250 - LdrpFindOrMapDll - ENTER: DLL name: C:\WINDOWS\SYSTEM32\kernelbase.dll
00c0:1200 @ 02106250 - LdrpResolveDllName - ENTER: DLL name: C:\WINDOWS\SYSTEM32\kernelbase.dll
00c0:1200 @ 02106250 - LdrpResolveDllName - RETURN: Status: 0x00000000
00c0:1200 @ 02106250 - LdrpFindOrMapDll - RETURN: Status: 0x00000000
00c0:1200 @ 02106250 - LdrpFindOrMapDependency - RETURN: Status: 0x00000000
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlSetLastWin32Error" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlLeaveCriticalSection" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlEnterCriticalSection" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlInitializeCriticalSection" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlDeleteCriticalSection" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "RtlQueryPerformanceCounter" by name
00c0:1200 @ 02106250 - LdrpGetProcedureAddress - INFO: Locating procedure "LdrResolveDelayLoadedAPI" by name
00c0:1200 @ 02106250 - LdrpMergeNodes - INFO: Merging a cycle rooted at USER32.dll.
00c0:1200 @ 02106250 - LdrpMergeNodes - INFO: Adding cyclic module GDI32.dll.
(c0.1200): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
ntdll!LdrInitShimEngineDynamic+0x330:
00007ffc`d68732e8 cc int 3
0:000>
You should link statically with the CRT. For a consumer application there are a lot of scenarios which result in particular DLL missing or its configuration botched. I was the installer technical lead for a very popular Windows application (thousands of installs per day) and you would not believe how common misconfigured Windows machines are out there. At the bottom I'll give a short list.
The universal CRT is a good idea but relatively new and it will be a while, (possibly a long while) until it being broken prevents your customers' PC from booting. That should be the threshold: If your customer cannot log in without DLL X then it is ok to depend on it.
Common Weird states:
Pretty important to keep in mind that this is not a hotfix. It is a normal update that is automatically delivered through Windows Update. So there's one fact you know, these machines are not being maintained. That's Very Bad News of course and having problems is to be expected.
It is an operating system DLL that is normally supplied along with the operating system install, starting with Win7. That ought to narrow down what's wrong with these machines, they are likely to boot XP. Small odds for Vista. XP is no longer maintained by Microsoft so seeing the update missing is not a coincidence.
That's fine but you need to double-check this in your installer and refuse to install on XP. Targeting XP is still possible, you have to change the Platform Toolset setting to "v140_xp". Not sure if that option is available in the Community edition, it would surprise me if it was.
Only one counts, ucrtbase.dll. The rest of them are the api-ms-win*.dll files that ought to be present in the Windows install directory. They are included so you can still get it going on XP and Vista, you should deploy these to c:\windows\system32 or c:\windows\syswow64, depending on the bitness. Do note that you documented the x64 directory, verifying that the user has a 64-bit version of Windows is another thing you have to double-check in your installer.
That is STATUS_DLL_INIT_FAILED, the DllMain() entrypoint of one of the DLLs you have a dependency on returned FALSE. Pretty bad news, not easy to debug and you certainly won't get anywhere trying to tackle this with VS2015 since it won't fail on your machine. You need to turn on loader snaps so the OS loader becomes chatty. Having access to a machine that has this problem is of course mandatory.
Yeah, time to cut your losses I'd say. Nobody can reasonably expect your app to work when they intentionally don't maintain their machine or refuse to update it. Verify in your installer that ucrtbase.dll is present and when it is not then just stop the install and tell them to update their machine first.