-1

My C++ program calls LoadLibraryEx() to load a third party DLL. The result is a null handle - it fails to load. A call to GetLastError() returns zero afterwards which isn't of much use but at least it's not a missing DLL file.

The code goes something like this:

 HINSTANCE instance = ::LoadLibraryExW(
     path, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
 if (instance == 0)
 {
     DWORD lastError = GetLastError();
     LOG( "Failed to load, error code is " +
         LastErrorAsString( lastError ));
     return E_FAIL;
 }

I cannot access that machine - I can only deploy code there and observe logs uploaded into network storage.

How would I programmatically find why the DLL fails to load?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 7
    Do you call `GetLastError` *directly* after you check for the `NULL` handle? You don't call any other function in between? – Some programmer dude Jul 25 '16 at 08:30
  • 1
    Can you please share the code rather than referencing the functions you are using. It'll help us try and isolate the issue for you. – Jonathon Ogden Jul 25 '16 at 08:31
  • @JonathonOgden Added a snippet – sharptooth Jul 25 '16 at 08:41
  • @JoachimPileborg Yes, that was the first thing I checked. – sharptooth Jul 25 '16 at 08:44
  • 4
    From MSDN: If this value is used and lpFileName specifies an absolute path, the system uses the alternate file search strategy discussed in the Remarks section to find associated executable modules that the specified module causes to be loaded. If this value is used and lpFileName specifies a relative path, the behavior is undefined. Are you sure that absolute path is used? – mooncheese Jul 25 '16 at 08:48
  • @mooncheese Yes, the absolute path is used - it's logged right before the call. – sharptooth Jul 25 '16 at 08:53
  • call 'RtlGetLastNtStatus()' after 'LoadLibraryExW' and which status it will return ? – RbMm Jul 25 '16 at 09:00
  • Very likely some third-party program interfering with yours. RbMm's suggestion of trying the unsupported LdrLoadDll as a troubleshooting step is probably sound. It may give you an error code, or the call might even succeed (in which case LoadLibraryEx is probably hooked). If you can get the system administrators to run Process Monitor and send you the results, that might also give you some clues. – Harry Johnston Jul 26 '16 at 02:17

3 Answers3

0

Probably your dll can be found but it has a dependency on a dll that cannot found on the remote machine.

If you cannot use Dependency Walker then you can try to use techniques as described in articles such as this:

How to determine a windows executables DLL dependencies programatically?

Community
  • 1
  • 1
mooncheese
  • 124
  • 1
  • 1
  • 4
  • 1
    in this case GetLastError must return ERROR_MOD_NOT_FOUND and/or RtlGetLastNtStatus - STATUS_DLL_NOT_FOUND - so this not explain – RbMm Jul 25 '16 at 09:20
  • see http://forums.codeguru.com/showthread.php?73880-LoadLibrary()-fails-but-GetLastError()-returns-0 It is not explanation but a direction to search. Anyway I recommend to serch why LoadLibraryExW returns null and GetLastError returns SUCCESS – mooncheese Jul 25 '16 at 09:28
  • this absolute not explain why GetLastError return 0 – RbMm Jul 25 '16 at 09:29
0

Okay, so I checked better - and indeed there was another WinAPI call which caused "last error" to be overwritten after LoadLibraryEx(). It was hidden deep inside several layers of C++ helper objects so I didn't notice it earlier. So it was a bug in the caller code and the real "last error" was non-zero.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • funny ) early you say that just called GetLastError() after LoadLibraryExW. however if you tried LdrLoadDll in test - this take only several minutes for all understand – RbMm Jul 26 '16 at 08:17
  • 3
    More to the point, if you'd posted the actual code rather than fake code we'd have spotted the problem immediately. I had actually thought of asking about that, but assumed that a 108k-rep user would know better. That'll teach me, I guess. – Harry Johnston Jul 26 '16 at 20:51
  • @HarryJohnston I know. I couldn't have posted the actual code because, first, it's proprietary code and second, it has a lot of dependencies. I was under impression that the code I posted was equivalent to the real one. What would you do in such situation? – sharptooth Jul 27 '16 at 07:22
  • Either (a) get permission to post the code snippet, or (b) test the code I was planning to post to make certain it actually reproduces the problem. At the very least you could have refrained from telling Joachim that this was "the first thing I checked". :-) – Harry Johnston Jul 27 '16 at 21:37
  • @HarryJohnston I honestly believed I ensured there were no WinAPI calls in between but it turned out I was wrong. – sharptooth Aug 01 '16 at 10:52
-1

It looks like the problem is likely to be third-party software that has installed a hook or other anti-virus measure, the hook might be buggy and not setting the correct last error code.

As a troubleshooting measure, you should try LdrLoadDll instead of LoadLibraryEx.

Note that this is an undocumented internal function, so you might prefer not to use it in production code, but it would be a useful troubleshooting step as it should produce a more useful error code.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
RbMm
  • 31,280
  • 3
  • 35
  • 56
  • 1
    When posting an answer suggesting to use undocumented internal functions, you should **explicitly** state this. While knowing the internals is helpful in diagnosing issues, solutions based on these implementation details are not generally helpful, and should be marked as *"unsupported"*, *"could break at any time"*, etc. – IInspectable Jul 25 '16 at 10:13
  • @IInspectable if we want investigate problem - use LdrLoadDll is best and most informative choice – RbMm Jul 25 '16 at 10:16
  • 2
    *"LdrLoadDll [...] is best [...] choice"* - That depends on your requirements. If you implement a fun project, and don't care, if a future Windows update breaks it, then go ahead and use it. If you write some mission-critical code, you certainly do **not** want to use unsupported system calls. It is not your responsibility to make that decision. It is, however, your responsibility to document, that the proposed solution is unsupported, so that a reader can make a decision based on this important detail. – IInspectable Jul 25 '16 at 10:24
  • @IInspectable - requirements - find why a DLL fails to load? only this. so all what you write not relatted – RbMm Jul 25 '16 at 10:25
  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/13113552) – Wernsey Jul 25 '16 at 12:17
  • 1
    @Wernsey question is "why a DLL fails to load?". if LdrLoadDll return status != 0 (<0) this status and answer to question. if returned status == 0, but HMODULE still 0 (dll actually not loaded) - we can be sure that some hooks installed in this Windows, that changed default behaviour. and this give to us more info, then using LoadLibraryEx/GetLastError only. – RbMm Jul 25 '16 at 12:26
  • 1
    @RbMm: What additional information does `LdrLoadDll` produce in this specific case, though? From your description, it doesn't sound like there is any more information, why the load failed. You're no wiser than had you called `LoadLibraryEx` and `GetLastError`. – IInspectable Jul 25 '16 at 17:45
  • 1
    @IInspectable i suspect some user mode hook in process, which fail dll load, but not correct set LastError. some times LoadLibraryEx can be hooked, but LdrLoadDll - no. (of course hook can be on all API). and NTSTATUS sometime more informative then win32 LastError (by lost accuracy). again if LdrLoadLibrary return 0 and HMODULE also 0 - 100% in process hook. try what i offered really help understand problem. and your religious taboo I do not understand and do not accept – RbMm Jul 25 '16 at 18:02
  • 1
    @IInspectable - sharptooth not ask "how me load DLL?", he ask "why DLL fail to load, but no error returned ?" so question in research, and here we can use special test code, which will be not included in release build. the best way here - look under debugger, but if this is impossible - the best way - try check LdrLoadDll. in clear windows impossible got 0 as status and 0 as HMODULE. if we got exactly this result - only hook, which modified windows behaviour can produce this result. if no - we have or error NTSTATUS which explain what happens – RbMm Jul 25 '16 at 18:19
  • 1
    @IInspectable or may be even dll will be loaded (if only LoadLibraryExW hooked).if you not agree with technical details or have better solution - interesting read it. writing about "unsupported" calls no sense – RbMm Jul 25 '16 at 18:19
  • 1
    `LdrLoadDll` (or `LdrLoadLibrary` as you call it in another comment) is undocumented. This makes it an unsupported system call. Failure to document the use of unsupported system calls in an answer leaves out important information, reducing its overall value. This Q&A site is visited by professionals as well. Show them some respect by catering to their needs. – IInspectable Jul 25 '16 at 18:43
  • 1
    @IInspectable - sorry for LdrLoadLibrary this of course slip of the pen. about LdrLoadDll like all another ntdll exports - "unsupported system calls" - nonsense. but main in another. question in RESEARCH problem. i offered concrete way how do this. you can nothing offer but permanent repeat religious taboo, which here at all not related – RbMm Jul 25 '16 at 18:55
  • 1
    @IInspectable based on current info(if it correct) - this is with almost 100% probability user mode in process hook. but for make this 100% clear - try and LdrLoadDll and look for NTSTATUS and HMODULE. if both 0 - exactly hook in this system. but possible result will be and another and this give very usefull info. however try check this or not - coice of sharptooth. – RbMm Jul 25 '16 at 19:03
  • Almost all professional programmers (and most competent amateur programmers) will want to avoid using undocumented system calls in production code unless absolutely necessary. You may think this is silly, but that's beside the point. Your answers should still respect the wishes of the vast majority of readers by making it clear when you are suggesting something that (depending on context) they might not want to do. You needn't use the word "unsupported" if that bothers you, "undocumented" will do. (They mean the same thing, really, but whatever.) – Harry Johnston Jul 26 '16 at 02:11
  • 1
    @HarryJohnston - sorry you at all understand question ?!? question in RESEARCH error. how many times this need reply. and i give advice how RESEARCH this problem - look for LdrLoadDll result. all what you and IInspectable write here absolute inadequately to problem – RbMm Jul 26 '16 at 08:07
  • 2
    Yes, I understood what you were saying, though probably only because of your reply to IInspectable's first comment, and you'll note I posted a comment to the OP seconding your suggestion. And twenty years ago, I might have posted an answer similar to this one. What I know now that I didn't know then is that it isn't enough to write what you mean, you *also* have to think about how the reader might interpret it. In this case, the typical reader isn't going to understand the context, and it will be interpreted as "if LoadLibrary doesn't work, try LdrLoadDll, it's heaps better". – Harry Johnston Jul 26 '16 at 20:55
  • 1
    What I should have done in the first place I guess is to rewrite your answer, I was reluctant at the time, but I'm pretty sure that I understand what you intended to say. You can of course revert the edit if you wish. Hopefully this will make it clear what I mean about making things clear to the typical reader. – Harry Johnston Jul 26 '16 at 20:57
  • @HarryJohnston thank for edit. i understand you and view that you exactly understand me. unfortunately i also have problem with english, as result frequently write not the best text for understanding – RbMm Jul 26 '16 at 21:25