【问题标题】:How do I print to the debug output window in a Win32 app?如何打印到 Win32 应用程序中的调试输出窗口?
【发布时间】:2010-11-22 22:36:36
【问题描述】:

我有一个已加载到 Visual Studio 2005 中的 win32 项目。我希望能够将内容打印到 Visual Studio 输出窗口,但我终生无法弄清楚如何.我已经尝试过 'printf' 和 'cout

是否有某种特殊的方式可以打印到 Visual Studio 输出窗口?

【问题讨论】:

  • 请注意,Visual Studio 输出窗口不是控制台。它们都是“带有文本的窗口”,但在幕后是不同的。
  • 如果 VS 输出窗口默认在每条消息之前显示源 cpp 的完整路径,请考虑 workaround for __ FILE __。

标签: c++ visual-studio winapi visual-studio-2005 console


【解决方案1】:

您可以使用OutputDebugStringOutputDebugString 是一个宏,根据您的构建选项映射到OutputDebugStringA(char const*)OutputDebugStringW(wchar_t const*)。在后一种情况下,您必须为函数提供一个宽字符串。要创建宽字符文字,您可以使用 L 前缀:

OutputDebugStringW(L"My output string.");

通常您会像这样将宏版本与_T 宏一起使用:

OutputDebugString(_T("My output string."));

如果您的项目配置为为 UNICODE 构建,它将扩展为:

OutputDebugStringW(L"My output string.");

如果您不是为 UNICODE 构建,它将扩展为:

OutputDebugStringA("My output string.");

【讨论】:

  • 完美!谢谢。不过,为了完整起见,我不得不这样做:OutputDebugString(TEXT("Hello console world")); .. 大概是由于某种与 unicode 相关的构建选项。
  • 请注意,您会发现从 sysinternals 获得调试视图很有用。即使 Visual Studio 未在盒子上运行(甚至未安装),这也允许您查看 ODS 输出
  • @CDT:这取决于myStr的类型。是char*wchar_t* 还是LPTSTR?假设它是char*,您只需调用OutputDebugStringA(myStr) 或将OutputDebugStringWwchar_t*OutputDebugStringLPTSTR 一起使用,如我的回答中所述。
  • @CDT:有什么比调用具有单个参数的函数更简单的方法,即您要输出的消息?是 ANSI/UNICODE 的复杂性吗?只需使用 OutputDebugString 并定义适当的预处理器符号以匹配您使用的字符的宽度,或者使用灵活的“T”类型,它允许您编译为 8 位和 16 位字符。
  • @MonaJalal:从您的评论中不清楚 screen 是什么,因此很难给您具体的建议。如果您调试您的进程,调试器将有办法显示调试输出。如果您使用 Visual Studio 作为调试器,则输出将显示在 Output 窗口中。要实际查看输出,您必须从 Show output from 下拉列表中选择 Debug。如果您出于某种原因在调试器之外运行您的进程,您可以使用DebugView 查看所有进程的调试输出。
【解决方案2】:

如果项目是 GUI 项目,则不会出现控制台。为了将项目更改为控制台,您需要转到项目属性面板并设置:

  • 在“linker->System->SubSystem”中,值“Console (/SUBSYSTEM:CONSOLE)
  • 在“C/C++->预处理器->预处理器定义”中添加“_CONSOLE”定义

此解决方案仅在您拥有经典的“int main()”入口点时才有效。

但如果您像我的情况(openGL 项目)一样,则无需编辑属性,因为这样效果更好:

AllocConsole();
freopen("CONIN$", "r",stdin);
freopen("CONOUT$", "w",stdout);
freopen("CONOUT$", "w",stderr);

printf 和 cout 将照常工作。

如果在创建窗口之前调用AllocConsole,控制台会出现在窗口后面,如果之后调用,控制台会出现在前面。

更新

freopen 已弃用,可能不安全。请改用freopen_s

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);

【讨论】:

  • EDITBIN 可以将子系统设置为CONSOLE,即使您使用的是WinMain 而不是int main()
  • @Zac。谢谢!以 AllocConsole() 开头的 4 行效果很好。加1。没有其他任何工作,尽管在使用 /SUBSYSTEM:CONSOLE 和/或 _CONSOLE 宏之前,我已经让控制台出现在 Win32 项目中。不知道为什么今天晚上宏不起作用。它与使用 Common Language Runtime Support (/clr) 有什么关系吗?
【解决方案3】:

要打印到real 控制台,您需要使用链接器标志/SUBSYSTEM:CONSOLE 使其可见。额外的控制台窗口很烦人,但出于调试目的,它非常有价值。

OutputDebugString 在调试器内部运行时打印到调试器输出。

【讨论】:

  • 你也可以使用 AllocConsole() 分配你自己的控制台
【解决方案4】:

如果要打印十进制变量:

wchar_t text_buffer[20] = { 0 }; //temporary buffer
swprintf(text_buffer, _countof(text_buffer), L"%d", your.variable); // convert
OutputDebugString(text_buffer); // print

【讨论】:

  • %u 用于未签名,%f 用于浮动,根据reference
【解决方案5】:

考虑使用 VC++ 运行时宏进行报告_RPTN() and _RPTFN()

您可以使用 CRTDBG.H 中定义的 _RPTn 和 _RPTFn 宏 替换使用 printf 语句进行调试。这些宏 当 _DEBUG 不存在时,会在您的发布版本中自动消失 已定义,因此无需将它们包含在#ifdefs 中。

示例...

if (someVar > MAX_SOMEVAR) {
    _RPTF2(_CRT_WARN, "In NameOfThisFunc( )," 
         " someVar= %d, otherVar= %d\n", someVar, otherVar );
}

或者你可以直接使用VC++运行时函数_CrtDbgReport, _CrtDbgReportW

_CrtDbgReport 和 _CrtDbgReportW 可以将调试报告发送到三个不同的目的地:调试报告文件、调试监视器( Visual Studio 调试器)或调试消息窗口。

_CrtDbgReport 和 _CrtDbgReportW 通过将参数 [n] 参数替换为格式来为调试报告创建用户消息 字符串,使用 printf 或 wprintf 定义的相同规则 职能。然后这些函数生成调试报告和 根据当前报告确定一个或多个目的地 为 reportType 定义的模式和文件。当报告被发送到 调试消息窗口,文件名、行号和模块名是 包含在窗口中显示的信息中。

【讨论】:

  • 值得添加到答案中或注意_RPTF0 可用于不希望在格式字符串之后传递任何变量的情况。另一方面,_RPTFN要求格式字符串后至少有一个参数。
【解决方案6】:

如果您需要查看广泛使用 printf 的现有程序的输出,而无需更改代码(或进行最小更改),您可以按如下方式重新定义 printf 并将其添加到公共头文件 (stdafx.h)。

int print_log(const char* format, ...)
{
    static char s_printf_buf[1024];
    va_list args;
    va_start(args, format);
    _vsnprintf(s_printf_buf, sizeof(s_printf_buf), format, args);
    va_end(args);
    OutputDebugStringA(s_printf_buf);
    return 0;
}

#define printf(format, ...) \
        print_log(format, __VA_ARGS__)

【讨论】:

  • 要小心,因为是静态缓冲区,这个函数是不可重入的,不能从不同的线程中使用。
【解决方案7】:

您的 Win32 项目可能是 GUI 项目,而不是控制台项目。这会导致可执行标头中的差异。因此,您的 GUI 项目将负责打开自己的窗口。不过,这可能是一个控制台窗口。调用AllocConsole()创建它,并使用Win32控制台函数写入它。

【讨论】:

    【解决方案8】:

    我自己在寻找一种方法来做到这一点,并想出了一个简单的解决方案。

    我假设您在 Visual Studio 中启动了一个默认的 Win32 项目(Windows 应用程序),它提供了一个“WinMain”函数。默认情况下,Visual Studio 将入口点设置为“SUBSYSTEM:WINDOWS”。您需要首先更改此设置:

    项目 -> 属性 -> 链接器 -> 系统 -> 子系统

    然后从下拉列表中选择“Console (/SUBSYSTEM:CONSOLE)”。

    现在,程序将无法运行,因为需要一个“main”函数而不是“WinMain”函数。

    所以现在您可以像通常在 C++ 中那样添加“主”函数。之后,要启动 GUI 程序,您可以从“main”函数内部调用“WinMain”函数。

    程序的开始部分现在应该如下所示:

    #include <iostream>
    
    using namespace std;
    
    // Main function for the console
    int main(){
    
        // Calling the wWinMain function to start the GUI program
        // Parameters:
        // GetModuleHandle(NULL) - To get a handle to the current instance
        // NULL - Previous instance is not needed
        // NULL - Command line parameters are not needed
        // 1 - To show the window normally
        wWinMain(GetModuleHandle(NULL), NULL,NULL, 1); 
    
        system("pause");
        return 0;
    }
    
    // Function for entry into GUI program
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        // This will display "Hello World" in the console as soon as the GUI begins.
        cout << "Hello World" << endl;
    .
    .
    .
    

    Result of my implementation

    现在您可以在 GUI 程序的任何部分使用函数输出到控制台以进行调试或其他目的。

    【讨论】:

      【解决方案9】:

      您也可以使用WriteConsole方法在控制台打印。

      AllocConsole();
      LPSTR lpBuff = "Hello Win32 API";
      DWORD dwSize = 0;
      WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuff, lstrlen(lpBuff), &dwSize, NULL);
      

      【讨论】:

        【解决方案10】:

        这适用于 MSVC 下的 C++,甚至适用于通过调试器运行的 GUI 应用程序。它也完全从发布版本中省略。它甚至使用 C++ 字符串流进行灵活输入。

        #include <iostream>
        
        #ifdef _MSC_VER
        #include "Windows.h"
        #endif
        
        #if !defined(NDEBUG) && defined(_MSC_VER)
        #define LOG(args) {std::stringstream _ss; _ss << __FILE__ << "@" << __LINE__ << ": " \
            << args << std::endl; OutputDebugString(_ss.str().c_str());}
        #else
        #define LOG(args)
        #endif
        

        像这样使用:

        LOG("some message " << someValue);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-12
          • 1970-01-01
          • 2011-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多