?
Solved

Notification of Missing DLL's from a child process

Posted on 1999-01-04
15
Medium Priority
?
545 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
  • 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's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
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.
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses
Course of the Month14 days, 15 hours left to enroll

840 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