在发布模式下Console.SetOut存在问题?

14

我在我的代码中有很多Console.WriteLines,我可以在运行时观察它们。我还与一个我编写的本地库通信。

我想在本地库中添加一些printf并观察它们。然而,在运行时我看不到它们。

我创建了一个复杂的Hello World应用程序来演示我的问题。当应用程序运行时,我可以调试到本地库并看到Hello World被调用。然而输出永远不会出现在TextWriter里。请注意,如果以控制台应用程序的方式运行相同的代码,则一切正常工作。

C#:

    [DllImport("native.dll")]
    static extern void Test();

    StreamWriter writer;

    public Form1()
    {
        InitializeComponent();

        writer = new StreamWriter(@"c:\output.txt");
        writer.AutoFlush = true;
        System.Console.SetOut(writer);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Test();
    }

并且还有本地部分:

__declspec(dllexport) void Test()
{
    printf("Hello World");
}

更新: 下方的hamishmcn开始谈论调试/发布构建。我从上面的button1_click方法中删除了本机调用,并将其替换为标准的Console.WriteLine .net调用。当我以调试模式编译并运行时,消息被重定向到输出文件。然而,当我切换到发布模式时,调用没有被重定向。控制台重定向似乎只在调试模式下起作用。我应该如何解决这个问题?


没有答案,但是这篇文章http://stackoverflow.com/questions/2570001/allow-native-dll-to-output-stdout-stderr-in-c-console-application表明它应该可以正常工作。嗯。听起来像是stdout被重定向到了其他地方;要么就是被缓冲了。 - Steven Mackenzie
1
你是如何启动/附加到本地库的? - chilltemp
我已经通过vs.net连接到了进程,也让它在控制台上运行,但是我没有看到任何来自本机stdout的输出。我还尝试了DbgView,但它也没有输出任何本机内容,只有我的.net消息。 - Matt Jacobsen
1
但是你的代码是如何工作的呢?它是使用 PInvoke 调用本地库的 .Net 控制台应用程序吗? - CodeRipper
这是一个巨大的WindowsForms应用程序,但为了调试目的,我们启用控制台/调试输出到窗口 - 我可以在这里看到所有的Console.WriteLine和Debug.WriteLine消息。本地库通过PInvoke调用。 - Matt Jacobsen
+1 让我更爱 C# :) - abatishchev
4个回答

2
也许您的本地库由于某种原因不知道控制台。您可以尝试调用GetConsole 看看是否返回了句柄。如果没有,您可以尝试分配自己的控制台 看看是否有效。祝你好运!:-)
更新:
我也写了一个示例应用程序(控制台 C# 应用程序调用本机 C++ dll),C# Console.WriteLine 和本机 printf 都出现在控制台上...所以我们错过了什么吗?
您总是在调试模式下运行它吗?如果在发布模式下运行,您能看到控制台窗口吗?
更新2:
抱歉,我应该说我在控制台上看到了文本,但是如果我将控制台输出设置为 StreamWriter,就像您在示例中所做的那样,那么只有 WriteConsole 文本会进入输出文件,printf 仍然会输出到屏幕上。

请参见https://dev59.com/BUbRa4cB1Zd3GeqPyDRg。 - abatishchev
abatishchev: 这只是另一个随机函数调用。不想开玩笑,但我的简单printf调用到底有什么问题? - Matt Jacobsen
我现在有些困惑。让我试着澄清一下:根据你的建议,我离题了并尝试了 GetStdHandle,这返回了一个有效的标准输出句柄。我的程序的 c 组件实际上只是一个库——它没有控制台窗口,因此 AllocConsole/WriteConsole 无法帮助。但这不应该妨碍它通过 printf 或其他方式写入 stdout。 - Matt Jacobsen
这意味着尝试使用WriteConsole是没有用的 :) - Matt Jacobsen
我也写了一个示例应用程序(控制台C#应用程序调用本地C++ dll),并且C# Console.WriteLine和本地printf都出现在控制台上...那么我们缺少什么呢?...您是否总是以调试模式运行它 - 如果在发布模式下运行它,您是否看到控制台窗口? - hamishmcn
显示剩余3条评论

1

目前我没有任何项目可以尝试这个,但我肯定会怀疑缓冲。如果我没记错的话,stdout是有缓冲区的。每次它到达行末时都会刷新缓冲区:

printf("Should be flushed immediatelly\n");

或者您可以使用 fflush 来刷新 stdout:

printf("Will be buffered and then flushed");
fflush(stdout);

您也可以使用setbuf关闭缓冲:

setbuf(stdout, NULL);

1

控制台重定向只在调试模式下起作用。


0

在vsnprintf的基础上实现您自己的printf(来处理肮脏的细节),将内容写入控制台:

#include <stdarg.h>

int printf(const char *fmt, ...)
{
    char buffer[LARGESIZE];
    int rv;
    va_list ap;
    va_start(ap, fmt);
    rv = vsnprintf(buffer, sizeof(buffer), fmt, ap);
    va_end(ap);

    Console.WriteLine(buffer);

    return rv;
}

好主意。只是不要称其为 printf()(因为它并不是)。 - DevSolar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接