我正在构build一个Win32 GUI应用程序。 在这个应用程序中,我使用了一个旨在用于命令行应用程序的DLL。
假设Foo.exe是我的GUI应用程序,而bar()是在DLL中输出“hello”到stdout的函数。 Foo.exe调用bar()。
如果我使用redirect(>)(即Foo.exe > out.txt
)从命令行运行Foo.exe,它将“hello”写入out.txt并正常退出(如预期的那样)。
但是,如果我运行没有redirect的Foo.exe(无论是从cmd.exe还是通过在Windows资源pipe理器中双击),它会在调用bar()时崩溃。
如果我在debugging器中使用命令行中的redirect(通过VS的项目属性设置)运行Foo.exe并调用“GetStdHandle(STD_OUTPUT_HANDLE)”,我得到一个合理的句柄地址。 如果我没有在命令行中redirect,我得到0。
我需要什么来“初始化”标准吗? 有没有办法,我可以在应用程序启动设置此redirect? (redirect到一个文件将是理想的,但只是抛出由DLL打印的数据也可以。)
最后,我怀疑DLL是通过类似于POSIX的API写入stdout的,因为它是一个跨平台的DLL。 我不知道这是否重要。
我已经尝试使用CreateFile创build一个文件,并调用SetStdHandle,但似乎没有工作。 但是,我可能会错误地创build文件。 看下面的代码。
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); // hStdOut is zero HANDLE hFile; hFile = CreateFile(TEXT("something.txt"), // name of the write GENERIC_WRITE, // open for writing 0, // do not share NULL, // default security CREATE_NEW, // create new file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template BOOL r = SetStdHandle(STD_OUTPUT_HANDLE, hFile) ; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); // hStdOut is now equal to hFile, and r is 1 bar(); // crashes if there isn't a redirect in the program arguments
更新:我刚刚发现这篇文章: http : //support.microsoft.com/kb/105305 。 它声明“请注意,这段代码不能纠正句柄0,1和2的问题。实际上,由于其他复杂性,不可能纠正这个问题,因此有必要使用streamI / O而不是低级别的I / O“。
我的DLL肯定使用文件句柄0,1和2.所以,这个问题可能没有很好的解决scheme。
我正在开发一个解决scheme来检查这种情况,并使用CreateProcess正确地重新启动exe。 我完成后会在这里发帖。
我找到的解决方案如下:
请注意,我没有测试完全这个序列,但稍有不同。
我不知道是否有些步骤是多余的。
在任何情况下,下面的文章都很好地解释了文件句柄,描述符字符流的概念:
您必须使用/SUBSYSTEM
开关将foo.exe构建为控制台应用程序。 Windows将自动为您的应用程序分配一个控制台(stdout),这可以是:
如果您将foo.exe作为GUI应用程序构建,则控制台不会默认分配,这将解释崩溃
如果您必须使用GUI子系统,则仍然可以使用AllocConsole完成。 这个旧的WDJ文章有示例代码来帮助你。
你能告诉我你使用哪个图书馆吗? 这个问题有很好的解决办法 写小的存根发射EXE(在GUI模式,但没有窗户!)有你的图标,所有的捷径启动。 将这个存根EXE“CreateProcess”作为重定向输出的实际EXE为“NUL”或“CON”,或者它的CreateProcess()被挂起,取其STDOUT,不做任何事情。 这样,你原来的EXE应该没有可见的控制台工作,但实际上会有写入的地方 – 在父级不可见存根EXE所取的句柄0,1和2中。 请注意,杀死父EXE可能会使孩子失去了手柄和崩溃。
您可能最终在任务管理器中有两个进程。 所以你可以尝试让这两个过程像Google Chrome那样工作。
在你的问题上我需要一些“初始化”标准吗? – 只有你的父母/发射器可以预先初始化您的标准输出为手柄0,1和2“正常”。