2012-01-06 76 views
3

好的......燒壞了這個......整天都在撓我的腦袋。我有一個非常簡單的單用途C++ DLL(StartApplication.dll),用於啓動應用程序。Windows 7 - CreateProcess w/DEBUG_PROCESS訪問衝突

  • 在WinXP中工作正常,但不是在Win7
  • 使用的CreateProcess()與DEBUG_PROCESS(這樣我就可以等待程序結束前完成)。
  • 如果我監視任務管理器進程,我可以看到進程的開始,但沒有創建窗口,並沒有進一步發生
  • 如果我改變NORMAL_PRIORITY_CLASS,該方案將作爲其應該執行(但我失去的能力,終止,因爲我只能做到這一點的同時調試)
  • 錯誤代碼給我STATUS_ACCESS_VIOLATION前等着
  • 我有UAC關閉,設定可執行以管理員身份運行,並與WinXP的兼容性不做任何

繼承人代碼。任何想法,將不勝感激

//...blah blah...handful of stuff preceding this to set up command line and 
    //directories etc....not of use here probably... 

SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(SECURITY_ATTRIBUTES); 
sa.bInheritHandle = TRUE; 

STARTUPINFO si = {0}; si.cb = sizeof(si); 
si.dwFlags = STARTF_USESTDHANDLES; 

si.hStdOutput = (NULL == stdOutFileName)? INVALID_HANDLE_VALUE : 
    ::CreateFile(stdOutFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa 
     , CREATE_ALWAYS, 0, NULL); 

si.hStdError = (NULL == stdErrFileName)? INVALID_HANDLE_VALUE : 
    ::CreateFile(stdErrFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa 
     , CREATE_ALWAYS, 0, NULL)   
PROCESS_INFORMATION pi = {0}; 
if (::CreateProcess(useApplicationName? applicationName : NULL, processCommandLine 
    , NULL, NULL, TRUE, /*NORMAL_PRIORITY_CLASS*/DEBUG_PROCESS, NULL, currentDirectory, &si, &pi)) 
{ 
    BOOL cont = TRUE; 
    while (cont) 
    { 
     DWORD continueStatus = DBG_CONTINUE; 

     DEBUG_EVENT debugEvent = {0}; 
     if (!::WaitForDebugEvent(&debugEvent, INFINITE)) 
     { 
      errorCode = ErrorCode_Other; 
      ::TerminateProcess(pi.hProcess, 0); 
      break; 
     } 
     else 
     { 
      switch (debugEvent.dwDebugEventCode) 
      { 
       case EXCEPTION_DEBUG_EVENT: 
        switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) 
        { 
         case EXCEPTION_ACCESS_VIOLATION: 
         case EXCEPTION_DATATYPE_MISALIGNMENT: 
         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 
         case EXCEPTION_FLT_DENORMAL_OPERAND: 
         case EXCEPTION_FLT_DIVIDE_BY_ZERO: 
         case EXCEPTION_FLT_INEXACT_RESULT: 
         case EXCEPTION_FLT_INVALID_OPERATION: 
         case EXCEPTION_FLT_OVERFLOW: 
         case EXCEPTION_FLT_STACK_CHECK: 
         case EXCEPTION_FLT_UNDERFLOW: 
         case EXCEPTION_INT_DIVIDE_BY_ZERO: 
         case EXCEPTION_INT_OVERFLOW: 
         case EXCEPTION_PRIV_INSTRUCTION: 
         case EXCEPTION_IN_PAGE_ERROR: 
         case EXCEPTION_ILLEGAL_INSTRUCTION: 
         case EXCEPTION_NONCONTINUABLE_EXCEPTION: 
         case EXCEPTION_STACK_OVERFLOW: 
         case EXCEPTION_INVALID_DISPOSITION: 
         case EXCEPTION_INVALID_HANDLE: 
          errorCode = ErrorCode_ApplicationException; 
          *exceptionCode = debugEvent.u.Exception. 
           ExceptionRecord.ExceptionCode; 
          ::TerminateProcess(pi.hProcess, 0); 
          break; 
         default: 
          ; 
        } 
        break; 

       case EXIT_PROCESS_DEBUG_EVENT: 
        cont = FALSE; 
        break; 
       default: 
        ; 
      } 
      ::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId 
       , continueStatus); 
     }  
    } 

    ::GetExitCodeProcess(pi.hProcess, reinterpret_cast<LPDWORD>(exitCode)); 

    ::CloseHandle(pi.hProcess); 
    ::CloseHandle(pi.hThread); 
} 
if (INVALID_HANDLE_VALUE != si.hStdOutput) 
    ::CloseHandle(si.hStdOutput); 
if (INVALID_HANDLE_VALUE != si.hStdError) 
    ::CloseHandle(si.hStdError); 

return errorCode; 

}

回答

3

你的代碼終止的全過程的第一個異常occures後。 通常情況下,您應該讓程序處理異常,只有當異常未處理時,過程纔會終止。

要查看是否有異常情況較爲嚴重(即不處理周圍的第一次。)檢查u.Exception.dwFirstChance

  • 如果爲0,設置相應的錯誤代碼和終止。
  • 否則,第一次發生異常,您應該撥打ContinueDebugEventDBG_EXCEPTION_NOT_HANDLED將異常傳遞給進程。

編輯

如果你只是想觀看例外,而不是從調試器內處理它們,你應該總是繼續DBG_EXCEPTION_NOT_HANDLED

有一個陷阱:

主線程開始前右時,Windows提出這需要傳遞給過程(DBG_CONTINUE)的INT3異常。

僞代碼:

bool FirstInt3 = true; 

while (cont) 
{ 
    DWORD continueStatus = DBG_EXCEPTION_NOT_HANDLED; 

    // .... 

    switch(...) 
    { 
     case EXCEPTION_DEBUG_EVENT: 
      if(!FirstChance) 
      { 
       // Fatal exception 

       // Log Exception that terminated the program here 
       // Don't do anything else, Windows automatically terminates the process 
       // You will get an EXIT_PROCESS_DEBUG_EVENT on the next event 
      } 
      switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode) 
      { 
       case EXCEPTION_BREAKPOINT: 
        if(FirstInt3) 
        { 
         FirstInt3 = false; 
         continueStatus = DBG_CONTINUE; 
         break; 
        } 
       default: 
        // Log ExceptionCode here 
        break; 
      } 
      break; 
    } 
+0

@Ajay:我添加了「.dwFirstChance!= 0」條件,在EXCEPTION_DEBUG_EVENT開關中的終止之前設置continueStatus。它只是做另一個循環,並在下一個循環終止。我自己編寫了一個新手(我原本沒有寫這個),所以如果我把它放在一個不好的地方,那麼讓我知道。 (或者如果有一部分流程我可以完全乾掉)。如果我重新排列的東西,我可以讓cmd窗口根據需要彈出,但它會掛起,直到終止時纔會執行任何操作。可能我需要設置某種Windows 7權限才能正確執行? – 0xDEADFACE 2012-01-12 16:15:48

+0

@ 0xDEADFACE更新了我的答案,希望澄清一點。 – pezcode 2012-01-12 16:35:10

+0

啊,我們走了。處理INT3異常是那裏的缺失鏈接。不得不稍微調整一下,以便優雅地處理終止事件,但這很像一種魅力。感謝一羣人。 – 0xDEADFACE 2012-01-12 19:17:23

1

@pezcode是正確的 - 不只是在結束接收來自調試第一個例外的過程中,讓它正常運行。調試器(您的代碼)無論如何都會收到調試對象中發生的所有異常(第一次機會異常)。

我建議你首先儘量減少調試器循環邏輯,並儘量不要附加和處理來處理。先保持簡單,然後繼續前進。

2

如果我正確地理解了你,你正在使用DEBUG_PROCESS,這樣你就可以等到進程退出。這是主要的矯枉過正。

要等到進程退出,請在pi.hProcess上使用WaitForSingleObject(或適當的其他等待函數)。

+0

以及我需要發回任何異常代碼,所以調試過程是必要的。我想我的介紹中措辭不佳 – 0xDEADFACE 2012-01-12 16:03:48