【问题标题】:Trap Windows application crash and flush file buffers捕获 Windows 应用程序崩溃并刷新文件缓冲区
【发布时间】:2011-08-03 16:53:46
【问题描述】:

这个问题有点远,但我想也许有人知道一个聪明的解决方案。

我在 Windows 中使用 RTS 游戏(Kane's Wrath)有一个特殊情况,它可以保存重播文件。不利的对手有可能在游戏中引发崩溃。在这种情况下,拥有尽可能完整的回放文件将是有利的。

但是,回放文件输出似乎是缓冲的,并且只出现在 4096 字节的集合中(这是很多游戏时间)。我想知道是否有可能以某种方式强制程序在发生崩溃时刷新其所有文件句柄。是否有一些内置的操作系统功能允许禁用应用程序的缓冲?

如果做不到这一点,我可能想为这个问题编写一个启动器/包装器。我想它应该注入一些代码,a)为崩溃安装信号处理程序(是 SIGSEGV 吗?),b)重定向CreateFile(我知道程序使用跟踪跟踪)来存储句柄。然后崩溃处理程序将使用FlushFileBuffers 刷新所有处理程序。

或者是否有可能获得另一个进程的打开文件句柄?

这是否有可能奏效,您能否就如何以最少的干扰最好地实现这一目标给我任何建议?


小更新: @CatPlusPlus 建议 Detours 挂钩程序,拦截文件打开调用并将其修改为无缓冲。这可能是解决方案!

【问题讨论】:

  • 没有内置的操作系统功能可以做到这一点,怎么可能呢?操作系统甚至不知道缓冲正在发生——它所看到的是,每隔一段时间,有人说“嘿,我想向这个文件写入 4096 字节”并且它做到了。
  • @Adam:嗯,类似于在 Linux 上你有 ulimit 告诉程序不要做某些事情。我想也许操作系统可以说,“对于下一个进程,我们禁用所有 IO 缓冲”,因为 IO 最终使用系统调用。

标签: c++ winapi crash flush


【解决方案1】:

您可以先将 winmain 包装在 try/catch 块中,如本文所述 文章:

XCrashReport : Exception Handling and Crash Reporting - Part 1

基本上是这样的:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
    int Result = -1;
    __try
    {
        Result = HandledWinMain(hInstance, NULL, lpstrCmdLine, nCmdShow);
    }

    __except(RecordExceptionInfo(hInstance,GetExceptionInformation(), "main thread"))
    {
        // Do nothing here - RecordExceptionInfo() has already done
        // everything that is needed. Actually this code won't even
        // get called unless you return EXCEPTION_EXECUTE_HANDLER from
        // the __except clause.
    }

    return Result;
}

当然我不确定你的缓冲区的状态是什么,但这会让你进入这个过程。

【讨论】:

  • 我可以用这个捕获另一个程序的异常吗?请记住,我没有游戏程序的源代码,只有可执行文件。我必须以某种方式获取可执行文件的文件句柄并捕获崩溃。
  • 不确定是否可以不附加调试器,并且可能不会给您任何有用的东西,您可能还想看到这个答案:stackoverflow.com/questions/2385859/…
【解决方案2】:

假设进程不是你的, 您唯一的选择似乎是挂钩 WriteFile 函数,而是执行 WriteFile 后跟 Flush。
WriteFile 可以通过 IAT 直接挂钩或使用像 eashook 这样的库来挂钩。

【讨论】:

  • 感谢您的提示!我正在考虑挂钩 CreateFile 并将标志更改为无缓冲,根据 MSDN,这“就像在每次写入后调用 FlushFileBuffers 但效率更高”...
【解决方案3】:

我唯一能想到的就是在其汇编器输出中附加一个调试器和修补程序。

我记得当一些程序在我身上崩溃时这样做:跳过有问题的机器指令到函数的末尾,然后让它运行。在大约 50% 的情况下,这将使程序达到可以保存数据的程度。当然,之后重新启动是强制性的。

【讨论】:

  • 嗯,我希望能够将它作为一个包装游戏的单一启动器应用程序或类似的东西发布,所以如果可能的话它应该是非交互式的......
猜你喜欢
  • 1970-01-01
  • 2012-05-18
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多