【问题标题】:Windows 7 - CreateProcess w/ DEBUG_PROCESS Access ViolationWindows 7 - CreateProcess w/DEBUG_PROCESS 访问冲突
【发布时间】:2012-02-04 13:54:24
【问题描述】:

好的...在这个上精疲力尽...整天抓挠我的头。我有一个非常简单的、单一用途的 c++ DLL (StartApplication.dll) 用于启动应用程序。

  • 在 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;

}

【问题讨论】:

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


    【解决方案1】:

    您的代码在第一个异常发生后终止整个过程。 通常你应该让程序处理异常,只有当异常没有被处理时进程才会终止。

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

    • 如果为 0,请相应设置错误代码并终止。
    • 否则,第一次出现异常,应调用ContinueDebugEventDBG_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;
        }
    

    【讨论】:

    • @Ajay 也是:我添加了“.dwFirstChance != 0”条件,在 EXCEPTION_DEBUG_EVENT 开关中的终止之前设置 continueStatus。它只是执行另一个循环并在下一个循环中终止。我对自己编码有点新手(我最初没有写这个),所以如果我把它放在一个不好的地方,然后让我知道。 (或者如果有部分过程我可以完全核对)。如果我重新安排事情,我可以根据需要弹出 cmd 窗口,但它会挂起并且在终止之前什么都不做。我可能需要设置某种 Windows 7 权限才能正确执行吗?
    • @0xDEADFACE 更新了我的答案,希望能澄清一点。
    • 啊,我们走了。处理 INT3 异常是那里缺少的链接。不得不稍微调整一下以优雅地处理终止,但这就像一个魅力。谢谢一群人。
    • @0xDEADFACE 很高兴我能帮上忙。 PS:你可以通过点击它旁边的复选标记来接受正确的答案
    • @0xDEADFACE 您介意通过 PM 或电子邮件将您的 c++ 代码发送给我吗?我遇到了同样的问题(Stefan Olson 的启动画面?),但我在 C++ 中不太擅长根据 pezcode 在这里写的内容找到解决方案。
    【解决方案2】:

    如果我对您的理解正确,您使用 DEBUG_PROCESS 只是为了等到进程退出。这太夸张了。

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

    【讨论】:

    • 嗯,我确实需要发回任何异常代码,所以调试过程是必要的。我想我的介绍中的措辞不佳
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2021-12-18
      • 2012-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多