driver-online
  log-inmypagesitemap
top
   Խ
   α׺
    ߿
    ý
    Beginning Driver
    &
   CrashDumpм(beta)
   QnA
    WDM Թ
    USB
    NDIS
    File System
    Debugging
    
 

GUI hang ߻ Windows application ã dump ϱ
 ·ۼ 2008.08.05:09.32 (ȭ)  · ۼ Jeff  · ȸ 5,938


" http://blogs.msdn.com/ntdebugging blog ̸ ڷᰡ ֽϴ. ڷ ǰ ֽñ blog 湮Ͻ ֽϴ. (http://blogs.msdn.com/ntdebugging/archive/2007/05/29/detecting-and-automatically-dumping-hung-gui-based-windows-applications.aspx)"

GUI hang ߻ Windows application ã dump ϱ

Jeff Dailey ۼ

̸ Jeff ̰ CPR Platform Escalation Engineer Դϴ. Tate Hang α׿ ̾ hang мϴ ؼ ̾߱ ϰ մϴ. machine debug ְ lab ̰ hang ã dump ִ Ȯ Դϴ. ߰ hang ߻ϴ ؼ badwindows.zpi ̶ Ͽ ÷ ְ ˷帱 Դϴ.

 

GUI Hangs

windows, button, scroll bar GUI Windows application ߴ (۾ڿ ) ˴ϴ. Application Ǿ ü մϴ. ׷ Application Window ٽ ׷ ʰ Ű Է¿ ʽϴ. ׸ ӵ ʰ Ͻ ߻ϱ⵵ մϴ. Application Ϸ翡 10 – 30 Ǵ ֽϴ. ׸ ð ų ֽϴ.

ϱ GUI Windows Application ٸ α׷ Message queue ޽ ϴ ϴ ˾ƾ մϴ. Windows Application ϳ main thread message ó մϴ. ׸ WinMain Ǿ ֽϴ. Thread ޹ Message diaglog ų ٸ thread ų mouse click ۿ ٸ Window ޽ ϴ ٸ ϰ ˴ϴ.

Application · Ϲ ɸ call ȣϴ Դϴ. Thread ޹ message ó Ѵٸ hang ǥõ Դϴ. Process dump ִٸ Cdb Windbg ~0s KB ϸ message ó block Ǿ ְų Ȯ Դϴ. Thread 0 message óϴ thread ƴ϶ ~*kb Ͽ Thread stack ȮϿ ã ֽϴ.

Cdb windbg Ͽ ð dump ų debugger Ͽ dump ذ Ʒ tool ֽϴ.

tool

hang ó ذ ϰڽϴ.

Visual Studio (The Express edition ), Windows SDK (), debugger SDK (Debugging tools ġ), ׸ Windows ۿ ذ ʿ մϴ.

 

debug application ϴ Ͱ Ϳ ô.

1.     ϱⰡ ϴ.

2.     ü ߰ų ʽϴ. ̰ CPU Resource ʴ´ٴ Դϴ.

3.     Hang ¿ ִ Ǵϱ ð ֽϴ.

4.     ߸ ϰ ִ Application dump ֽϴ.

5.     ټ ڸ ó dump ʽϴ. ̰ user temp ̾߱ մϴ.

6.     ѵ dump Ͽ harddisk ϰ ʽϴ.

7.     Event log hang dump õ event մϴ.

8.     Hang ã binary ֽϴ.

9.      

ϴ°?

dumphungwindow.exe consol application ϴ. Dump ϵ loop ̸ ð window SendMessageTimeout Ͽ Message Դϴ. Timeout Application ʴ´ٸ dump ϰ event log Դϴ.

Dumphungwindow.zip ϰ badwindow.zip Ʒ ٿ ֽϴ. Exe ϰ Visual studio 2005 project ҽ ֽϴ. project dumphungwindow Ҹ badwindow test ֽϴ. project 3 ٸ hang ־ Test ֽϴ.

The command line options are as follows.

C:\source\dumphungwindow\debug>dumphungwindow.exe /?
 This sample application shows you how to use the debugger
 help api to dump an application if it stop responding.

 This tool depends on dbghelp.dll, this comes with the Microsoft debugger tools on www.microsoft.com

 Please make sure you have the debugger tools installed before running this tool.
 This tool is based on sample source code and is provided as is without warranty.

 feel free to contact jeffda@microsoft.com to provide feedback on this sample application

 /m[Number] Default is 5 dumps

 The max number of dumps to take of hung windows before exiting.

 /t[Seconds]  Default is 5 seconds

 The number of seconds a window must hang before dumping it.

 /p[Seconds] Default is 0 seconds

 The number of seconds to pause when dumping before continuing scan.

 /s[Seconds] Default is 5 seconds.

 The scan interval in seconds to wait before rescanning all windows.

 /d[DUMP_FILE_PATH] The default is the SystemRoot folder

 The path or location to place the dump files.

 /e[EXECUTABLE NAME] This allows you to start another program if an application hangs

Dumphungwindow.exe ϱ Ʒ ϸ ˴ϴ.

C:\source\dumphungwindow\debug>dumphungwindow.exe
Dumps will be saved in C:\Users\jeff\AppData\Local\Temp\
scanning for hung windows

****

bad application ϱ ؼ dumphungwindows.zip Badwindowapp.zip ϸ ˴ϴ. badwindow.exe menu hang / hang type 2 ϸ ˴ϴ. ʰ findhungwindow ʴ badwindow.exe ã dump Դϴ.

 

 

 

Hung Window found dumping process (7064) badwindow.exe

Dumping unresponsive process

C:\Users\jeffda\AppData\Local\Temp\HWNDDump_Day5_29_2007_Time10_36_38_Pid7064_badwindow.exe.dmp

 

 

hung window ã ּ ޾ Ұ dump ϴ ð Source Ȯ ֽʽÿ.

 

Dumphungwindow badwindow ٿ ޾ Ͻʽÿ. Hang type 1 ֽʽÿ. Hang type 1 ؼ blog ٷ ְ ؼ blog ϵ ϰڽϴ. Dump Ǿٸ windbg file \ open crash dump Ͽ Ȯ ֽϴ.

 

tool ս ã ϱ⸦ ٶϴ.

 

մϴ. Jeff

/********************************************************************************************************************

Warranty Disclaimer

--------------------------

This sample code, utilities, and documentation are provided as is, without warranty of any kind. Microsoft further disclaims all

implied warranties including without limitation any implied warranties of merchantability or of fitness for a particular  purpose.

The entire risk arising out of the use or performance of the product and documentation remains with you.

 

In no event shall Microsoft be liable for any damages whatsoever  (including, without limitation, damages for loss of business

profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to

use the sample code, utilities, or documentation, even if  Microsoft has been advised of the possibility of such damages.

Because some states do not allow the exclusion or limitation of liability for consequential or incidental damages, the above

limitation may not apply to you.

 

********************************************************************************************************************/

 

#include <stdio.h>

#include <windows.h>

#include <dbghelp.h>

#include <psapi.h>

 

// don't warn about old school strcpy etc.

#pragma warning( disable : 4996 )

 

int iMaxDump=5;

int iDumpsTaken=0;

int iHangTime=5000;

int iDumpPause=1;

int iScanRate=5000;

HANDLE hEventLog;

char * szDumpLocation;

int FindHungWindows(void);

char * szDumpFileName = 0;

char * szEventInfo = 0;

char * szDumpFinalTarget = 0;

char * szModName = 0;

char * szAppname = 0;

DWORD dwExecOnHang = 0;

 

#define MAXDUMPFILENAME 1000

#define MAXEVENTINFO 5000

#define MAXDUMPFINALTARGET 2000

#define MAXDUMPLOCATION 1000

#define MAXAPPPATH 1000

#define MAXMODFILENAME 500

#define HMODSIZE 255

 

int main(int argc, char * argv[])

{

      int i;

      int z;

      size_t j;

      char scan;

 

      // check to make sure we have dbghelp.dll on the machine.

      if(!LoadLibrary("dbghelp.dll"))

      {

            printf("dbghelp.dll not found please install the debugger tools and place this tool in \r\nthe debugging tools directory or a copy of dbghelp.dll in this tools directory\r\n");

            return 0;

      }

 

      // Allocate a buffer for our dump location

      szDumpLocation = (char *)malloc(MAXDUMPLOCATION);

      {

            if(!szDumpLocation)

            {

            printf("Failed to alloc buffer for szdumplocation %d",GetLastError());

            return 0;

            }

      }

 

      szAppname = (char *)malloc(MAXAPPPATH);

      {

            if(!szAppname)

            {

            printf("Failed to alloc buffer for szAppname  %d",GetLastError());

            return 0;

            }

      }

 

      // We use temp path because if we are running under terminal server sessions we want the dump to go to each

      // users secure location, ie. there private temp dir. 

      GetTempPath(MAXDUMPLOCATION, szDumpLocation );

     

      for (z=0;z<argc;z++)

      {

            switch(argv[z][1])

            {

            case '?':

                  {

                  printf("\n This sample application shows you how to use the debugger \r\n help api to dump an application if it stop responding.\r\n\r\n");

                  printf("\n This tool depends on dbghelp.dll, this comes with the Microsoft debugger tools on www.microsoft.com");

                  printf("\n Please make sure you have the debugger tools installed before running this tool.");

                  printf("\n This tool is based on sample source code and is provided as is without warranty.");

                  printf("\n feel free to contact jeffda@microsoft.com to provide feedback on this sample application\r\n\r\n");

                  printf(" /m[Number] Default is 5 dumps\r\n The max number of dumps to take of hung windows before exiting.\r\n\r\n");

                  printf(" /t[Seconds]  Default is 5 seconds\r\n The number of seconds a window must hang before dumping it. \r\n\r\n");

                  printf(" /p[Seconds] Default is 0 seconds\r\n The number of seconds to pause when dumping before continuing scan. \r\n\r\n");

                  printf(" /s[Seconds] Default is 5 seconds.\r\n The scan interval in seconds to wait before rescanning all windows.\r\n\r\n");

                  printf(" /d[DUMP_FILE_PATH] The default is the SystemRoot folder\r\n The path or location to place the dump files.  \r\n\r\n");

                  printf(" /e[EXECUTABLE NAME] This allows you to start another program if an application hangs\r\n\r\n");

 

                  return 0;

                  }

            case 'm':

            case 'M':

                  {

                        iMaxDump = atoi(&argv[z][2]);

                        break;

                  }

            case 't':

            case 'T':

                  {

                        iHangTime= atoi(&argv[z][2]);

                        iHangTime*=1000;

                        break;

                  }

            case 'p':

            case 'P':

                  {

                        iDumpPause= atoi(&argv[z][2]);

                        iDumpPause*=1000;

                        break;           

                  }

            case 's':

            case 'S':

                  {

                        iScanRate = atoi(&argv[z][2]);

                        iScanRate*=1000;             

                        break;

                  }

            case 'd':

            case 'D':

                  { // Dump file directory path

                        strcpy(szDumpLocation,&argv[z][2]);

                        j = strlen(szDumpLocation);

 

                        if (szDumpLocation[j-1]!='\\')

                        {

                              szDumpLocation[j]='\\';

                              szDumpLocation[j+1]=NULL;

                        }

                        break;

                  }

            case 'e':

            case 'E':

                  { // applicaiton path to exec if hang happens

                        strcpy(szAppname,&argv[z][2]);

                        dwExecOnHang = 1;

                        break;

                  }

            }

      }

 

 

      printf("Dumps will be saved in %s\r\n",szDumpLocation);

      puts("scanning for hung windows\n");

 

      hEventLog = OpenEventLog(NULL, "HungWindowDump");

 

      i=0;

      scan='*';

      while(1)

      {

            if(i>20)

            {

                  if ('*'==scan)

                  {

                  scan='.';

            }

                  else

                  {

                  scan='*';

            }

                  printf("\r");

            i=0;

            }

            i++;

            putchar(scan);

            if(!FindHungWindows())

            {

                  return 0;

            }

            if (iMaxDump == iDumpsTaken)

            {

                  printf("\r\n%d Dumps taken, exiting\r\n",iDumpsTaken);

                  return 0;

            }

            Sleep(iScanRate);

      }

 

      free(szDumpLocation);

      return 0;

}

 

int FindHungWindows(void)

{

DWORD dwResult = 0;

DWORD ProcessId = 0;

DWORD tid = 0;

DWORD dwEventInfoSize = 0;

 

// Handles

HWND hwnd = 0;

HANDLE hDumpFile = 0;

HANDLE hProcess = 0;

HRESULT hdDump = 0;

 

SYSTEMTIME SystemTime;

MINIDUMP_TYPE dumptype = (MINIDUMP_TYPE) (MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData);

 

// These buffers are presistant.

 

// security stuff to report the SID of the dumper to the event log.

PTOKEN_USER pInstTokenUser;

HANDLE ProcessToken;

TOKEN_INFORMATION_CLASS TokenInformationClass = TokenUser;

DWORD ReturnLength =0;

 

// This allows us to get the first window in the chain of top windows.

hwnd = GetTopWindow(NULL);

if(!hwnd)

{

      printf("Could not GetTopWindow\r\n");

      return 0;

}

 

// We will iterate through all windows until we get to the end of the list.

while(hwnd)

{

      // Get the process ID for the current window   

      tid = GetWindowThreadProcessId(hwnd, &ProcessId);

 

      // Sent a message to this window with our timeout. 

      // If it times out we consider the window hung

      if (!SendMessageTimeout(hwnd, WM_NULL, 0, 0, SMTO_BLOCK, iHangTime, &dwResult))

      {

            // SentMessageTimeout can fail for other reasons, 

            // if it's not a timeout we exit try again later

            if(ERROR_TIMEOUT != GetLastError())

            {

                  printf("SendMessageTimeout has failed with error %d\r\n",GetLastError());

                  return 1;

            }

                  // Iint our static buffers points.

                  // On our first trip through if we have not

                  // malloced memory for our buffers do so now.

                  if(!szModName)

                  {

                        szModName = (char *)malloc(MAXMODFILENAME);

                        {

                              if(!szModName)

                              {

                              printf("Failed to alloc buffer for szModName %d",GetLastError());

                              return 0;

                              }

                        }

                  }

                  if(!szDumpFileName)// first time through malloc a buffer.

                  {

                        szDumpFileName = (char *)malloc(MAXDUMPFINALTARGET);

                        {

                              if(!szDumpFileName)

                              {

                                    printf("Failed to alloc buffer for dumpfilename %d",GetLastError());

                                    return 0;

                              }

                        }

                  }

                  if(!szDumpFinalTarget)// first time through malloc a buffer.

                  {

                        szDumpFinalTarget= (char *)malloc(MAXDUMPFINALTARGET);

                        {

                              if(!szDumpFinalTarget)

                              {

                              printf("Failed to alloc buffer for dumpfiledirectory %d",GetLastError());

                              return 0;

                              }

                        }

                  }

                  if(!szEventInfo)

                  {

                        szEventInfo= (char *)malloc(MAXEVENTINFO);

                        {

                              if(!szEventInfo)

                              {

                              printf("Failed to alloc buffer for szEventInfo %d",GetLastError());

                              return 0;

                              }

                        }

                  }

                  // End of initial buffer allocations.

 

            GetLocalTime (&SystemTime);

           

            // Using the process id we open the process for various tasks.

            hProcess = OpenProcess(PROCESS_ALL_ACCESS,NULL,ProcessId);

            if(!hProcess )

            {

                  printf("Open process of hung window failed with error %d\r\n",GetLastError());

                  return 1;

            }

            // What is the name of the executable?

            GetModuleBaseName( hProcess, NULL, szModName,MAXMODFILENAME);

 

            printf("\r\n\r\nHung Window found dumping process (%d) %s\n",ProcessId,szModName);

 

            // Here we build the dump file name time, date, pid and binary name

            sprintf(szDumpFileName,"HWNDDump_Day%d_%d_%d_Time%d_%d_%d_Pid%d_%s.dmp",SystemTime.wMonth,SystemTime.wDay,SystemTime.wYear,SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond,ProcessId,szModName);

            strcpy(szDumpFinalTarget,szDumpLocation);

            strcat(szDumpFinalTarget,szDumpFileName);

 

            // We have to create the file and then pass it's handle to the dump api

            hDumpFile = CreateFile(szDumpFinalTarget,FILE_ALL_ACCESS,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

            if(!hDumpFile)

            {

                  printf("CreateFile failed to open dump file at location %s, with error %d\r\n",szDumpLocation,GetLastError());

                  return 0;

            }

 

            printf("Dumping unresponsive process\r\n%s",szDumpFinalTarget);

           

            // This dump api will halt the target process while it writes it's

            // image to disk in the form a dump file.

            // this can be opened later by windbg or cdb for debugging.

            if(!MiniDumpWriteDump(hProcess,ProcessId,hDumpFile,dumptype ,NULL,NULL,NULL))

            {

                  // We do this on failure

                  hdDump = HRESULT_FROM_WIN32(GetLastError());

                  printf("MiniDumpWriteDump failed with a hresult of %d last error %d\r\n",hdDump,GetLastError());

                  CloseHandle (hDumpFile);

                  return 0;

            }

            else

            {

                  // If we are here the dump worked.  Now we need to notify the machine admin by putting a event in

                  // the application event log so someone knows a dump was taken and where it is stored.

                  sprintf(szEventInfo,"An application hang was caught by findhungwind.exe, the process was dumped to %s",szDumpFinalTarget);

 

                  // We need to get the process token so we can get the user sit so ReportEvent will have the

                  // User name / account in the event log.

                  if (OpenProcessToken(hProcess,      TOKEN_QUERY,&ProcessToken ) )

                  {

                        // Make the firt call to findout how big the sid needs to be.    

                        GetTokenInformation(ProcessToken,TokenInformationClass, NULL,NULL,&ReturnLength);

                        pInstTokenUser = (PTOKEN_USER) malloc(ReturnLength);

                        if(!pInstTokenUser)

                        {

                              printf("Failed to malloc buffer for InstTokenUser exiting error %d\r\n",GetLastError());

                              return 0;

                        }

                        if(!GetTokenInformation(ProcessToken,TokenInformationClass, (VOID *)pInstTokenUser,ReturnLength,&ReturnLength))

                        {

                              printf("GetTokenInformation failed with error %d\r\n",GetLastError());

                              return 0;

                        }

                  }

                  // write the application event log message. 

                  // This will show up as source DumpHungWindow

                  dwEventInfoSize=(DWORD)strlen(szEventInfo);

     

                  ReportEvent(hEventLog,EVENTLOG_WARNING_TYPE,1,1,pInstTokenUser->User.Sid,NULL,dwEventInfoSize,NULL,szEventInfo);

 

                  // Free to token buffer, we don't want to leak anything.

                  free(pInstTokenUser);

                 

                  // In additon to leaking a handle if you don't close the handle

                  // you may not get the dump to flush to the hard drive.

                  CloseHandle (hDumpFile);

                  printf("\r\nDump complete");

                 

                  // This allows you to execute something if you get a hang like crash.exe

                  if (dwExecOnHang)

                  {

                        system(szAppname);

                  }

                 

                  //  The Sleep is here so in the event you want to wait N seconds

                  //  before collecting another dump

                  //  you can pause.  This is helpful if you want to see if any

                  //  forward progress is happening over time

                 

                  Sleep(iDumpPause);

            }

            // Once we are at our threadshold for max dumps

            // we exit so we do not fill up the hard drive.

            iDumpsTaken++;

            if (iMaxDump == iDumpsTaken)

            {

                  return 0;

            }

        }

        // This is where we traverse to the next window.

            hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);

      }

      return 1;

}

 

*亯 Ѿ ƼԴϴ.
 
  

: Hresult Win32 Error code ȯϱ

: Desktop Heap Overview


· Hang Windows ã ֱ.
...
2008.08.19 ڸƮ
 
quick-menu
event
study
QnA
pds
family-site concert used used2 intro
address
address