Windows 7 - 具有DEBUG_PROCESS访问冲突的CreateProcess

时间:2012-01-06 21:08:37

标签: c++ windows visual-studio windows-7 windows-xp

好吧......烧掉了这一天......整天都在挠头。我有一个非常简单的单用途c ++ DLL(StartApplication.dll)用于启动应用程序。

  • 在WinXP中运行良好,但在win7中运行不正确
  • 使用带有DEBUG_PROCESS的CreateProcess()(所以我可以在终止之前等待程序完成)。
  • 如果我在任务管理器中监视进程,我可以看到进程启动,但没有创建窗口,也没有进一步发生
  • 如果我更改为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 个答案:

答案 0 :(得分:3)

您的代码在第一个异常发生后终止整个过程。 通常情况下,您应该让程序处理异常,只有在未处理异常时才会终止该过程。

要查看异常是否致命(即第一次未处理),请检查u.Exception.dwFirstChance

  • 如果为0,请相应地设置错误代码并终止。
  • 否则,首次发生异常,您应该使用ContinueDebugEvent致电DBG_EXCEPTION_NOT_HANDLED,将异常传递给流程。

修改

如果您只想查看异常而不是从调试器内部处理异常,则应始终继续使用DBG_EXCEPTION_NOT_HANDLED

有一个问题:

在主线程启动之前,Windows引发了一个INT3异常,需要传递到进程(DBG_CONTINUE)。

伪代码:

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;
    }

答案 1 :(得分:2)

如果我理解正确,那么您正在使用DEBUG_PROCESS,以便您可以等到该进程退出。这是一个重大的过度杀伤。

要等到进程退出,请在pi.hProcess上使用WaitForSingleObject(或其他适当的等待函数)。

答案 2 :(得分:1)

@pezcode是对的 - 不要只是从调试对象接收第一个异常结束进程,让它正常运行。无论如何,调试器(您的代码)将接收调试对象中发生的所有异常(第一次机会异常)。

我建议你首先最小化调试器循环逻辑,并且尽量不要附加和处理进程。先保持简单,然后继续前进。