Como faço para imprimir na janela de saída de depuração em um aplicativo Win32?

97

Eu tenho um projeto win32 que carreguei no Visual Studio 2005. Gostaria de poder imprimir coisas na janela de saída do Visual Studio, mas não consigo descobrir como. Eu tentei 'printf' e 'cout <<', mas minhas mensagens permanecem teimosamente não impressas.

Existe algum tipo de maneira especial de imprimir na janela de saída do Visual Studio?

izb
fonte
11
Observe que a janela de saída do Visual Studio não é o console. Ambos são "janelas com texto", mas são diferentes nos bastidores.
MSalters em

Respostas:

136

Você pode usar OutputDebugString. OutputDebugStringé uma macro que, dependendo das opções de construção, mapeia para OutputDebugStringA(char const*)ou OutputDebugStringW(wchar_t const*). No último caso, você terá que fornecer uma ampla cadeia de caracteres para a função. Para criar um literal de caractere largo, você pode usar o Lprefixo:

OutputDebugStringW(L"My output string.");

Normalmente, você usará a versão macro junto com a _Tmacro, como este:

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

Se o seu projeto estiver configurado para construir para UNICODE, ele se expandirá para:

OutputDebugStringW(L"My output string.");

Se você não estiver construindo para UNICODE, ele se expandirá para:

OutputDebugStringA("My output string.");
Martin Liversage
fonte
2
Perfeito! Obrigado. Para completar, porém, descobri que eu tinha que fazer isso: OutputDebugString (TEXT ("Hello console world")); .. presumivelmente devido a algum tipo de opção de construção relacionada ao Unicode.
izb
1
note que você achará útil ter debugview do sysinternals. Isso permite que você veja a saída do ODS mesmo se o Visual Studio não estiver em execução (ou mesmo instalado) na caixa
pm100,
4
@CDT: Depende do tipo de myStr. É char*, wchar_t*ou LPTSTR? Assumindo que é char*que você simplesmente chamar OutputDebugStringA(myStr)ou usar OutputDebugStringWcom wchar_t*e OutputDebugStringcom LPTSTRcomo explicado na minha resposta.
Martin Liversage
1
@CDT: O que é mais simples do que chamar uma função com um único parâmetro que é a mensagem que você deseja enviar? É a complexidade ANSI / UNICODE? Apenas use OutputDebugStringe defina os símbolos apropriados do pré-processador para coincidir com a largura dos caracteres que você usa ou vá com os tipos "T" flexíveis que permitem que você compile para caracteres de 8 e 16 bits.
Martin Liversage
1
@MonaJalal: O seu comentário não deixa claro qual é a tela, então é um pouco difícil fornecer conselhos específicos. Se você depurar seu processo, o depurador terá uma maneira de exibir a saída de depuração. Se você estiver usando o Visual Studio como seu depurador, a saída será mostrada na janela Saída . Para realmente ver a saída, você deve selecionar Depurar na lista suspensa Mostrar saída . Se você, por algum motivo, estiver executando seu processo fora de um depurador, poderá usar DebugView para ver a saída de depuração de todos os processos.
Martin Liversage
29

Se o projeto for um projeto GUI, nenhum console aparecerá. Para transformar o projeto em um console, você precisa ir ao painel de propriedades do projeto e definir:

  • Em " vinculador-> Sistema-> Subsistema ", o valor " Console (/ SUBSISTEMA: CONSOLE) "
  • Em " C / C ++ -> Pré-processador-> Definições de pré-processador " adicione o " definição " _CONSOLE "

Esta solução funciona apenas se você tiver o clássico " ponto de entrada int main () ".

Mas se você for como no meu caso (um projeto openGL), você não precisa editar as propriedades, pois funciona melhor:

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

printf e cout funcionarão normalmente.

Se você chamar AllocConsole antes da criação de uma janela, o console aparecerá atrás da janela, se você chamá-lo depois, ele aparecerá à frente.

Atualizar

freopenestá obsoleto e pode não ser seguro. Use em seu freopen_slugar:

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Zac
fonte
EDITBINpode definir subsistema para CONSOLEaté mesmo se você estiver usando em WinMainvez de int main().
Ben Voigt
1
@Zac. Obrigado! As 4 linhas começando com AllocConsole () funcionaram muito bem. Mais 1 para isso. Nada mais estava funcionando, embora eu tenha conseguido que os consoles aparecessem em projetos Win32 antes de usar as macros / SUBSYSTEM: CONSOLE e / ou _CONSOLE antes. Não sei por que as macros não funcionaram esta noite. Isso poderia ter algo a ver com o uso do Common Language Runtime Support (/ clr) ?
riderBill
12

Para imprimir no realconsole, você precisa torná-lo visível usando o sinalizador do vinculador /SUBSYSTEM:CONSOLE. A janela extra do console é irritante, mas para fins de depuração é muito valiosa.

OutputDebugString imprime na saída do depurador ao executar dentro do depurador.

Tocando
fonte
6
Você também pode alocar seu próprio console usando AllocConsole ()
Billy ONeal
4

Considere o uso de macros de tempo de execução VC ++ para Reporting _RPT N () e _RPTF N ()

Você pode usar as macros _RPTn e _RPTFn, definidas em CRTDBG.H, para substituir o uso de instruções printf para depuração. Essas macros desaparecem automaticamente em sua versão de lançamento quando _DEBUG não é definido, portanto, não há necessidade de incluí-las em #ifdefs.

Exemplo...

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

Ou você pode usar as funções de tempo de execução do VC ++ _CrtDbgReport, _CrtDbgReportW diretamente.

_CrtDbgReport e _CrtDbgReportW podem enviar o relatório de depuração para três destinos diferentes: um arquivo de relatório de depuração, um monitor de depuração (o depurador do Visual Studio) ou uma janela de mensagem de depuração.

_CrtDbgReport e _CrtDbgReportW criam a mensagem do usuário para o relatório de depuração substituindo os argumentos argumento [n] na string de formato, usando as mesmas regras definidas pelas funções printf ou wprintf. Essas funções geram o relatório de depuração e determinam o destino ou destinos, com base nos modos de relatório atuais e no arquivo definido para reportType. Quando o relatório é enviado para uma janela de mensagem de depuração, o nome do arquivo, lineNumber e moduleName são incluídos nas informações exibidas na janela.

Autodidata
fonte
Vale a pena acrescentar à resposta ou observar que _RPTF0pode ser usado onde não se espera que nenhuma variável seja passada após a string de formato. A _RPTFNmacro, por outro lado, requer pelo menos um argumento após a string de formato.
amn
4

Se você deseja imprimir variáveis ​​decimais:

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

Se você precisar ver a saída de um programa existente que usou extensivamente printf sem alterar o código (ou com alterações mínimas), você pode redefinir printf como segue e adicioná-lo ao cabeçalho comum (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__)
vlad
fonte
1
tenha cuidado por causa do buffer estático, essa função não é reentrante e não pode ser usada em threads diferentes.
Nikazo
2

Seu projeto Win32 é provavelmente um projeto de GUI, não um projeto de console. Isso causa uma diferença no cabeçalho executável. Como resultado, seu projeto de GUI será responsável por abrir sua própria janela. Isso pode ser uma janela de console, no entanto. Chame AllocConsole()para criá-lo e use as funções do console Win32 para gravá-lo.

MSalters
fonte
2

Eu estava procurando uma maneira de fazer isso sozinho e descobri uma solução simples.

Presumo que você tenha iniciado um projeto Win32 padrão (aplicativo do Windows) no Visual Studio, que fornece uma função "WinMain". Por padrão, o Visual Studio define o ponto de entrada como "SUBSYSTEM: WINDOWS". Você precisa primeiro alterar isso indo para:

Projeto -> Propriedades -> Vinculador -> Sistema -> Subsistema

E selecione "Console (/ SUBSYSTEM: CONSOLE)" na lista suspensa.

Agora, o programa não será mais executado, pois uma função "principal" é necessária em vez da função "WinMain".

Portanto, agora você pode adicionar uma função "principal" como faria normalmente em C ++. Depois disso, para iniciar o programa GUI, você pode chamar a função "WinMain" de dentro da função "principal".

A parte inicial do seu programa deve ser semelhante a esta:

#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;
.
.
.

Resultado da minha implementação

Agora você pode usar funções de saída para o console em qualquer parte de seu programa GUI para depuração ou outros fins.

pops
fonte
2

Você também pode usar o método WriteConsole para imprimir no console.

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