Windows 在Win32 GUI应用程序中使用stdout:如果我没有';无法重定向到参数中的文件
我正在构建一个Win32 GUI应用程序。在那个应用程序中,我使用的是一个DLL,它原本打算在命令行应用程序中使用 假设Foo.exe是我的GUI应用程序,bar()是DLL中的一个函数,它向标准输出“hello”。Foo.exe调用bar() 如果我使用重定向(>)从命令行运行Foo.exe(即Windows 在Win32 GUI应用程序中使用stdout:如果我没有';无法重定向到参数中的文件,windows,user-interface,dll,stream,stdout,Windows,User Interface,Dll,Stream,Stdout,我正在构建一个Win32 GUI应用程序。在那个应用程序中,我使用的是一个DLL,它原本打算在命令行应用程序中使用 假设Foo.exe是我的GUI应用程序,bar()是DLL中的一个函数,它向标准输出“hello”。Foo.exe调用bar() 如果我使用重定向(>)从命令行运行Foo.exe(即Foo.exe>out.txt),它会将“hello”写入out.txt并正常退出(如预期) 但是,如果在没有重定向的情况下运行Foo.exe(从cmd.exe或在Windows资源管理器中双击),则调
Foo.exe>out.txt
),它会将“hello”写入out.txt并正常退出(如预期)
但是,如果在没有重定向的情况下运行Foo.exe(从cmd.exe或在Windows资源管理器中双击),则调用bar()时会崩溃
如果我在调试器中运行Foo.exe,并在命令行中使用重定向(通过项目的VS属性设置)并调用“GetStdHandle(STD_OUTPUT_HANDLE)”,我将获得一个合理的句柄地址。如果在命令行中没有重定向的情况下调用它,则得到0
我需要一些东西来“初始化”标准输出吗?有没有办法在应用程序启动时设置此重定向?(重定向到一个文件是很理想的。但是仅仅抛出DLL打印的数据也可以。)
最后,我怀疑DLL是通过CRT POSIX类API写入stdout的,因为它是一个跨平台DLL。我不知道这是否重要
我试着用CreateFile创建一个文件并调用SetStdHandle,但这似乎不起作用。但是,我可能创建的文件不正确。请参阅下面的代码
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
更新:我刚找到这篇文章:。它声明“请注意,此代码不会更正句柄0、1和2的问题。事实上,由于其他复杂性,无法更正此问题,因此有必要使用流I/O而不是低级I/O。”
我的DLL肯定使用文件句柄0、1和2。因此,这个问题可能没有好的解决办法
我正在开发一个解决方案,检查这种情况,并使用CreateProcess适当地重新启动exe。完成后,我将在此处发布。您必须使用该开关将foo.exe构建为控制台应用程序。Windows将自动为您的应用程序分配控制台(stdout),该控制台可以是:
- 当前控制台
- 对文件的重定向
- 到另一个程序STDIN的管道
如果必须使用GUI子系统,仍然可以使用AllocConsole完成。这个老家伙想帮你 我找到的解决方案如下:
- 以某种方式获取有效的文件句柄以指导标准输出。 让我们调用文件句柄“fh”。 (请注意,在Windows上,文件句柄与文件描述符不同)
- 将文件描述符与文件句柄与_open_osfhandle关联 (详情请参阅) 让我们调用“fd”这个新的文件描述符,一个int值
- 调用dup2将标准输出文件号与给定的文件描述符关联: dup2(fd,标准输出文件号)
- 创建与标准输出文件描述符关联的文件strem 文件*f=_fdopen(标准文件号,“w”)李>
- 将标准输出设置为f的内容: *标准输出=*f
- 对给定的文件句柄调用SetStdHandle: 设置TDHandle(标准输出句柄,ofh)李>
你能告诉我你用哪一个图书馆吗?这个问题有很好的解决办法。编写小存根启动器EXE(在GUI模式下,但没有窗口!),其中包含您的图标和所有快捷方式。使此存根EXE“CreateProcess”成为真正的EXE,并将输出重定向到“NUL”或“CON”,或者,将其挂起的CreateProcess()作为其标准输出,对其不做任何操作。这样,您的原始EXE应该在没有可见控制台的情况下工作,但实际上可以在父不可见存根EXE所使用的句柄0、1和2中写入。请注意,杀死父EXE可能会使子级丢失其句柄并崩溃 在任务管理器中可能会有两个进程。所以你可以试着让这两个进程像谷歌Chrome一样工作
关于你的问题,我是否需要一些东西来“初始化”标准输出只有您的父/启动器才能“正确”预初始化句柄0、1和2的标准输出。如果我添加
freopen(“two.txt”,“w”,标准输出)
在调用bar
之前,然后运行Foo.exe>one.txt
将bar
的输出转到two.txt。但是,如果我只是在没有重定向的情况下运行Foo.exe
Foo.exe,它仍然会崩溃。您可以将调用堆栈添加到问题中吗?谢谢您的评论。不幸的是,分配控制台似乎并不能解决问题。我相信这篇文章是相关的:。“请注意,此代码不会更正句柄0、1和2的问题。事实上,由于其他复杂性,无法更正此问题,因此有必要使用流I/O而不是低级I/O。”我相信将其构建为控制台应用程序将解决此问题。但是,我需要将其构建为GUI应用程序。而且,这是一个出货产品——有一个控制台弹出窗口并不理想。