15

I have a process which calls CreateProcess. It appears that CreateProcess returns nonzero indicating success. However, the HANDLE to the process then gets immediately set, indicating the process has exited. When I call GetExitCodeProcess, STATUS_DLL_NOT_FOUND is then returned.

I understand that a DLL is missing. I even know exactly which one. However, what I don't understand is how to figure that out programmatically.

I noticed that Windows will present a dialog saying that the process failed to start because it couldn't find the specified DLL (screenshot: http://www.mediafire.com/view/?kd9ddq0e2dlvlb9 ). In the dialog, Windows specifies which DLL is missing. However, I find no way to get that information myself programmatically.

If a process fails to start and would return STATUS_DLL_NOT_FOUND, how do I programmatically retrieve the library name to which the target process was linked which couldn't be found? That way I can automatically record in an error report what DLL appears to be missing or corrupt in a given installation.

Keith4G
  • 387
  • 2
  • 11
  • 1
    I wish I knew the answer. Dependency Walker does it, but it uses the debug API which requires a separate process and much jumping of hoops. (You can turn that dialog off, BTW, for example if your process runs unattended and you want it to fail cleanly rather than hang.) – Alan Stokes Aug 21 '13 at 20:12
  • 2
    possible duplicate ? http://stackoverflow.com/questions/597260/how-to-determine-a-windows-executables-dll-dependencies-programatically – Radu Chivu Aug 21 '13 at 20:15
  • 1
    This doesn't answer your question, but you can use the [`SetErrorMode()`](http://msdn.microsoft.com/library/ms680621) function to control whether or not Windows will display an error message dialog when a DLL fails to load; however, there's not way to access the data that would be displayed in the error dialog. – Adam Rosenfield Aug 21 '13 at 20:25
  • @AlanStokes, AdamRosenfield - eventually I will do that. Already found it out. But I'm far more interested in finding out the name of the DLL that couldn't be found. – Keith4G Aug 21 '13 at 20:36
  • 3
    Use SysInternals' ProcMon, you'll see it search for the DLL and not finding it. Or google "loader snaps" to see how to get a debugger to display loader notifications. – Hans Passant Aug 21 '13 at 22:07
  • @HansPassant I'd need to be able to do it without needing debug privileges – Keith4G Dec 30 '13 at 23:38
  • 2
    Then you need to change the way you use DLLs. You must use LoadLibrary() and GetProcAddress() so you diagnose failure and report it properly. Very painful, that's the price. – Hans Passant Dec 30 '13 at 23:45
  • What if it's a system DLL? – Keith4G Dec 30 '13 at 23:47
  • I have the same problem. I expected the failed CreateProcess to be able to enumerate the missing DLLs since that is the way Windows dialogs work. We know it can be done since Windows does it on fail, and does it sequentially. If there are four missing DLLs it pops up a dialog for each one, one after another telling you the name of the missing DLL. – rtischer8277 Mar 09 '21 at 23:06

5 Answers5

5

CreateProcess returns 0 indicating success.

CreateProcess() returns a BOOL, where 0 is FALSE, aka failure not success.

If a process fails to start and would return STATUS_DLL_NOT_FOUND, how do I programmatically retrieve the library name to which the target process was linked which couldn't be found?

Unfortunately, there is no API for that. Your only option would be to manually access and enumerate the executable's IMPORTS table to find out what DLLs it uses, and then recursively access and enumerate their IMPORTS tables, manually checking every DLL reference you find to see whether that DLL file exists on the OS's search path or not.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Double checked my code, you're right. I was citing it off the top of my head. CreateProcess() does return nonzero indicating success. Yay convoluted invocations and if statements. It's definitely GetExitCodeProcess() which is returning STATUS_DLL_NOT_FOUND. Thanks for the heads up though. I'll have to let my boss know the bad news. – Keith4G Aug 22 '13 at 02:17
3

The best way is to use loader snaps. Basically you use gflags.exe (which is included with windbg) to enable loader snaps; then, run the process with the debugger attached. Loader snaps will enable the loader to print out dbg messages of the process and it will print the failures.

gflags.exe -i yourcode.exe +sls
windbg yourcode.exe

I know this is not a "programmatic" way to find out the problem, but what the loader does is complicated, and you don't really want to be redoing its logic to find the failure. That is why loader snaps were invented.

sam msft
  • 537
  • 6
  • 17
  • 2
    That's disturbing. The only answer that stands a chance of reliably getting at the answer to the question gets a -1 vote... If you want to automate this, use CDB in place of WinDbg, and have it dump its output to a log file. A program can parse the log file. – IInspectable Dec 12 '19 at 19:03
2

If the dll is statically linked you can walk the iat and see if the dll exists. If the dll is dynamically loaded then starting the process suspended and hooking LoadLibrary (or instead of hooking emulate a debugger) is the only way I see.

Remko
  • 7,214
  • 2
  • 32
  • 52
2

Just since this is somehow the top stackoverflow result on Google for "STATUS_DLL_NOT_FOUND". How to trace and solve any random occurence:

Download SysInternals procmon64.exe (or just the entire set). After startup immediately hit the looking glass 'Stop capture' button (Ctrl+E). And 'Clear' (Ctrl+X).

Set filters for:

  • 'Process name' is to whatever the mentioned process name was (for me it was 'build-script-build.exe') [Add]
  • 'Result' is not 'SUCCESS' [Add]
  • 'Path' ends with '.dll' [Add] [OK]

Start capture again (Ctrl+E).

Run the thing that had a problem again (for me: build cargo). Google for the last listed DLL file.

For me that was VCRUNTIME140.dll, so I installed the VC++ 2015 to 2019 redistributable.

ProcMon is kind of like unix strace.

Henk Poley
  • 729
  • 8
  • 17
1

The very hard way would be: Parsing the .EXE and .DLL files and create the dependency tree of .DLL files.

I don't think there is a way to get a list of DLL files that are missing: When Windows finds one missing DLL file it stops loading so if one DLL file is missing you won't find out if more DLL files are missing.

Another problem you could have is that old DLL versions could have missing "exports" (functions). This is even harder to detect than the dependency tree.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38