Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Notification of Missing DLL's from a child process

Posted on 1999-01-04
15
Medium Priority
?
543 Views
Last Modified: 2013-11-20
Is there a way to get some kind of notification when the application fails because of missing DLL's when the Application is a child process?  I am using CreateProcess(..) to spawn the process and it returns TRUE even though the process fails because of missing DLL's.
0
Comment
Question by:traott
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 4
  • 2
15 Comments
 
LVL 6

Expert Comment

by:snoegler
ID: 1327180
Check out www.sysinternals.com, head for the source of
"DLLView". This is a tools which monitors the loaded DLL's of
each process. As far as i remember, they use a dynamic VXD
to do this.
This could be useful to you.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327181
To check the failure of process creation, simply try the following:
Use the 'hProcess' member of the 'PROCESS_INFORMATION' structure filled in by the 'CreateProcess()' call and use 'WaitForSingleObject()' with a short timeout - the object's state is signaled when it terminates, so 'WAIT_TIMEOUT' guarantees that it's still running, and 'WAIT_ABANDONED' indicates a failure...

0
 

Author Comment

by:traott
ID: 1327182
I am using WaitForSingleObject but it does not tell me why the process terminated.  This WAIT_ABANDONED signal telles me that something happened but not what.  I need to know specifically if a DLL is missing.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 86

Expert Comment

by:jkr
ID: 1327183
The problem is that there's no specific error code in Win32 that indicates to a 'parent process' that a process creation failed due to a missing DLL - even worse, child processes have no (documented) relation to their parents... Well, NT signals a 'STATUS_DLL_NOT_FOUND' (C0000135) to the started process, but to receive this exception, you'd have to be a debugger ;-)
0
 

Author Comment

by:traott
ID: 1327184
How do debuggers handle this exception?  If debuggers can handle this there has to be a way for my application to handle it.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327185
A debugger gets notified by a 'EXCEPTION_DEBUG_EVENT'. It calls 'WaitForDebugEvent()' after the process has been started and receives a 'DEBUG_EVENT' union, in which (in this case) 'dbgev.u.Exception.ExceptionRecord.ExceptionCode' holds 'STATUS_DLL_NOT_FOUND' (0xC0000135) when a DLL can't be located. BUT: You'll have to use 'CreateProcess( ..., DEBUG_ONLY_THIS_PROCESS,...)' to become a debugger... (and i don't know whether this status code is dispatched on Win9x...
0
 
LVL 6

Expert Comment

by:snoegler
ID: 1327186
It is ...
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327187
Thanx, snoegler. This status code is only #defined in 'ntstatus.h' (and in no VC++ header), so i wansn't sure...

traott - do you need some code to illustrate how to do it?
0
 

Author Comment

by:traott
ID: 1327188
I do not need any code, the implementation is fairly straight forward for this Idea.  This is just an after thought, but will this also tell me what DLL the process cannot find.  I do not really need it but it would be nice.
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327189
Do you thik i may lock the Q along with the code?
0
 

Author Comment

by:traott
ID: 1327190
Yes, do so. I appreciate the help on this question.
0
 
LVL 86

Accepted Solution

by:
jkr earned 400 total points
ID: 1327191
Thanx ;-)
BTW: The following source code is part of our own 'mini-debugger', i just removed the ImageHlp calls, simplified  and modified it to check for 'STATUS_DLL_NOT_FOUND' - NOTE that the function originally represented a thread!

#ifndef STATUS_DLL_NOT_FOUND
#define STATUS_DLL_NOT_FOUND      0xC0000135
#endif

ULONG      __stdcall      DbgThread      (      LPVOID      pv)
{
      DEBUG_EVENT      dbgev;

      char            acBuf            [      2048]; // should be sufficiant for demo purposes ;-)
      
      char            acModule      [      MAX_PATH];
      char*            pszModule      =      NULL;

      DWORD            dwStatus;

      HANDLE            hProcess      =      INVALID_HANDLE_VALUE;

      STARTUPINFO                  si;
      PROCESS_INFORMATION      pi;


      ZeroMemory      (      &si,      sizeof      (      STARTUPINFO));

      si.cb                  =      sizeof      (      STARTUPINFO);
      si.dwFlags            =      STARTF_USESHOWWINDOW;
      si.wShowWindow      =      SW_SHOWDEFAULT;

      if      (      !CreateProcess      (      NULL,
                                                --> your debuggee goes here (as you know ;-) <--,
                                                NULL,
                                                NULL,
                                                FALSE,
                                                DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE,
                                                GetEnvironmentStrings      (),
                                                NULL,
                                                &si,
                                                &pi
                                          )
            )
            {
                  printf      (      "ERROR starting '%s'\n", pJob->job.pszModule);
                  return      (      0);
            }

      CloseHandle      (      pi.hThread);
      CloseHandle      (      pi.hProcess);

      SetDebugErrorLevel      (      SLE_WARNING);

      while      (      WaitForDebugEvent      (      &dbgev,      INFINITE))
                  {
                        dwStatus      =      DBG_CONTINUE;


                        switch      (      dbgev.dwDebugEventCode)
                                    {
                                          case      EXCEPTION_DEBUG_EVENT            :

                                                      // the _initial_ breakpoit set by the system is to be avoided!!
                                                      if      (      EXCEPTION_BREAKPOINT !=      dbgev.u.Exception.ExceptionRecord.ExceptionCode)
                                                                  dwStatus      =      DBG_EXCEPTION_NOT_HANDLED;

                                                      if      (      STATUS_DLL_NOT_FOUND =      dbgev.u.Exception.ExceptionRecord.ExceptionCode)
                                                            {
                                                                  dwStatus      =      DBG_EXCEPTION_NOT_HANDLED;

                                                                  // a DLL couldn't be found....
                                                            }


                                                      break;

                                          case      CREATE_THREAD_DEBUG_EVENT   :


                                                      break;

                                          case      CREATE_PROCESS_DEBUG_EVENT  :


                                                      break;

                                          case      EXIT_THREAD_DEBUG_EVENT     :

                                                      break;

                                          case      EXIT_PROCESS_DEBUG_EVENT    :

                                                      break;

                                          case      LOAD_DLL_DEBUG_EVENT        :

                                                      break;

                                          case      UNLOAD_DLL_DEBUG_EVENT      :

                                                      break;

                                          case      OUTPUT_DEBUG_STRING_EVENT   :
                                                {
                                                      ULONG      ulBytes;
                                                      void*      pOutput      =      malloc      (      dbgev.u.DebugString.nDebugStringLength + 1);

                                                      ZeroMemory      (      pOutput, dbgev.u.DebugString.nDebugStringLength + 1);

                                                      ReadProcessMemory      (      hProcess,
                                                                                          dbgev.u.DebugString.lpDebugStringData,
                                                                                          pOutput,
                                                                                          dbgev.u.DebugString.nDebugStringLength,
                                                                                          &ulBytes
                                                                                    );

                                                      wsprintf      (      acBuf,
                                                                              "OUTPUT_DEBUG_STRING_EVENT, enc.: '%s', length == %d, data == '%s'",
                                                                                    dbgev.u.DebugString.fUnicode
                                                                              ?      "UNICODE"
                                                                              :      "ANSI",
                                                                              dbgev.u.DebugString.nDebugStringLength,
                                                                                    dbgev.u.DebugString.fUnicode
                                                                              ?      GetAnsiString      (      ( wchar_t*) pOutput)
                                                                              :      ( char*) pOutput
                                                                        );

                                                      free      (      pOutput);

                                                      break;
                                                }

                                          case      RIP_EVENT                   :

                                                      wsprintf      (      acBuf,
                                                                              "RIP_EVENT, error code == 0x%08x",
                                                                              dbgev.u.RipInfo.dwError
                                                                        );

                                                      break;

                                          default:      break;
                                    }


                        ContinueDebugEvent      (      dbgev.dwProcessId,      
                                                            dbgev.dwThreadId,
                                                            dwStatus
                                                      );
                  }

      return      (      0);
}

0
 
LVL 86

Expert Comment

by:jkr
ID: 1327192
yeek, excuse the formatting - as i pasted it into the edit box, it was nice, so i think EE is to blame ;-)
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327193
And, of course - feel free to ask if you have further questions on this issue...
0
 
LVL 86

Expert Comment

by:jkr
ID: 1327194
Oops, i just saw that 'GetAnsiString()' in the 'OUTPUT_DEBUG_STRING_EVENT' branch isn't defined, it's simply

char*   GetAnsiString   (   wchar_t*    pwstr)
{
    static  char    s_acBuf [   1024];

    int             nLen;

    if  (   !pwstr)
            return  (   "");

    if  (   nLen    =   wcslen  (   pwstr  + 1) >   1024)  
            return  (   "");

    if  (   !WideCharToMultiByte    (   CP_ACP,
                                        0,
                                        pwstr,
                                        -1,
                                        s_acBuf,
                                        nLen    *   2,
                                        NULL,
                                        NULL
                                    )
        )   return  (   "");

    return  (   s_acBuf);
}


0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
In this post we will learn different types of Android Layout and some basics of an Android App.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Video by: ITPro.TV
In this episode Don builds upon the troubleshooting techniques by demonstrating how to properly monitor a vSphere deployment to detect problems before they occur. He begins the show using tools found within the vSphere suite as ends the show demonst…

618 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question