Bagaimana cara mencetak ke jendela keluaran debug di aplikasi Win32?

98

Saya punya proyek win32 yang saya muat ke dalam Visual Studio 2005. Saya ingin dapat mencetak sesuatu ke jendela keluaran Visual Studio, tetapi saya tidak bisa selama hidup saya mencari tahu caranya. Saya sudah mencoba 'printf' dan 'cout <<' tetapi pesan saya tetap tidak tercetak.

Apakah ada cara khusus untuk mencetak ke jendela keluaran Visual Studio?

Izb
sumber
11
Perhatikan bahwa jendela keluaran Visual Studio bukanlah konsol. Keduanya adalah "jendela dengan teks di dalamnya", tetapi berbeda di belakang layar.
MSalters
Jika jendela keluaran VS secara default menampilkan jalur lengkap cpp sumber sebelum setiap pesan, pertimbangkan solusi untuk __ FILE __.
Laurie Stearn

Jawaban:

137

Anda bisa menggunakan OutputDebugString. OutputDebugStringadalah makro yang bergantung pada opsi build Anda, baik dipetakan ke OutputDebugStringA(char const*)atau OutputDebugStringW(wchar_t const*). Dalam kasus selanjutnya Anda harus menyediakan string karakter lebar ke fungsi tersebut. Untuk membuat literal karakter lebar, Anda dapat menggunakan Lawalan:

OutputDebugStringW(L"My output string.");

Biasanya Anda akan menggunakan versi makro bersama dengan _Tmakro seperti ini:

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

Jika proyek Anda dikonfigurasi untuk membangun UNICODE, itu akan diperluas menjadi:

OutputDebugStringW(L"My output string.");

Jika Anda tidak membangun untuk UNICODE, itu akan diperluas menjadi:

OutputDebugStringA("My output string.");
Martin Liversage
sumber
2
Sempurna! Terima kasih. Untuk kelengkapannya, ternyata saya harus melakukan ini: OutputDebugString (TEXT ("Hello console world")); .. mungkin karena semacam opsi build terkait unicode.
izb
1
perhatikan bahwa Anda akan merasakan manfaat memiliki debugview dari sysinternals. Ini memungkinkan Anda untuk melihat output ODS meskipun Visual Studio tidak berjalan (atau bahkan diinstal) di kotak
pm100
4
@ CDT: Itu tergantung pada jenis myStr. Apakah itu char*, wchar_t*atau LPTSTR? Dengan asumsi bahwa char*Anda hanya menelepon OutputDebugStringA(myStr)atau menggunakan OutputDebugStringWdengan wchar_t*dan OutputDebugStringdengan LPTSTRseperti yang dijelaskan dalam jawaban saya.
Martin Liversage
1
@ CDT: Apa yang lebih sederhana daripada memanggil fungsi yang memiliki parameter tunggal yaitu pesan yang ingin Anda keluarkan? Apakah kompleksitas ANSI / UNICODE? Cukup gunakan OutputDebugStringdan tentukan simbol preprocessor yang sesuai untuk menyesuaikan dengan lebar karakter yang Anda gunakan atau gunakan tipe "T" yang fleksibel yang memungkinkan Anda untuk mengkompilasi karakter 8 dan 16 bit.
Martin Liversage
1
@MonaJalal: Tidak jelas dari komentar Anda apa layar itu sehingga agak sulit untuk memberi Anda saran khusus. Jika Anda men-debug proses Anda, debugger akan memiliki cara untuk menampilkan keluaran debug. Jika Anda menggunakan Visual Studio sebagai debugger Anda, output ditampilkan di jendela Output . Untuk benar-benar melihat output Anda harus memilih Debug dari Show output from dropdown. Jika karena alasan tertentu Anda menjalankan proses di luar debugger, Anda dapat menggunakan DebugView untuk melihat keluaran debug dari semua proses.
Martin Liversage
29

Jika proyek tersebut adalah proyek GUI, tidak ada konsol yang akan muncul. Untuk mengubah proyek menjadi konsol, Anda perlu membuka panel properti proyek dan menyetel:

  • Dalam " linker-> System-> SubSystem " nilai " Konsol (/ SUBSYSTEM: CONSOLE) "
  • Di " C / C ++ -> Preprocessor-> Preprocessor Definitions " tambahkan definisi " _CONSOLE "

Solusi ini hanya berfungsi jika Anda memiliki titik masuk klasik " int main () ".

Tetapi jika Anda seperti dalam kasus saya (proyek openGL), Anda tidak perlu mengedit properti, karena ini berfungsi lebih baik:

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

printf dan cout akan bekerja seperti biasa.

Jika Anda memanggil AllocConsole sebelum pembuatan jendela, konsol akan muncul di belakang jendela, jika Anda memanggilnya setelahnya, konsol akan muncul di depan.

Memperbarui

freopensudah usang dan mungkin tidak aman. Gunakan freopen_ssebagai gantinya:

FILE* fp;

AllocConsole();
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
Zac
sumber
EDITBINdapat menyetel subsistem ke CONSOLEmeskipun Anda sedang menggunakan WinMaindaripada int main().
Ben Voigt
1
@Tokopedia Terima kasih! 4 baris yang dimulai dengan AllocConsole () bekerja dengan baik. Ditambah 1 untuk itu. Tidak ada yang berfungsi, meskipun saya sudah mendapatkan konsol untuk muncul sebelumnya di proyek Win32 sebelum menggunakan makro / SUBSYSTEM: CONSOLE dan / atau _CONSOLE sebelumnya. Tidak tahu mengapa makro tidak berfungsi malam ini. Mungkinkah ada hubungannya dengan menggunakan Common Language Runtime Support (/ clr) ?
riderBill
12

Untuk mencetak ke realkonsol, Anda harus membuatnya terlihat dengan menggunakan bendera linker /SUBSYSTEM:CONSOLE. Jendela konsol ekstra mengganggu, tetapi untuk tujuan debugging itu sangat berharga.

OutputDebugString mencetak ke keluaran debugger saat dijalankan di dalam debugger.

Dering
sumber
6
Anda juga dapat mengalokasikan konsol Anda sendiri menggunakan AllocConsole ()
Billy ONeal
5

Pertimbangkan untuk menggunakan Makro runtime VC ++ untuk Pelaporan _RPT N () dan _RPTF N ()

Anda dapat menggunakan makro _RPTn, dan _RPTFn, yang ditentukan di CRTDBG.H, untuk menggantikan penggunaan pernyataan printf untuk debugging. Makro ini secara otomatis menghilang dalam build rilis Anda ketika _DEBUG tidak ditentukan, jadi tidak perlu menyertakannya dalam #ifdefs.

Contoh...

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

Atau Anda dapat menggunakan fungsi runtime VC ++ _CrtDbgReport, _CrtDbgReportW secara langsung.

_CrtDbgReport dan _CrtDbgReportW dapat mengirim laporan debug ke tiga tujuan yang berbeda: file laporan debug, monitor debug (Visual Studio debugger), atau jendela pesan debug.

_CrtDbgReport dan _CrtDbgReportW membuat pesan pengguna untuk laporan debug dengan mengganti argumen [n] ke dalam format string, menggunakan aturan yang sama yang ditentukan oleh fungsi printf atau wprintf. Fungsi ini kemudian membuat laporan debug dan menentukan tujuan atau tujuan, berdasarkan mode laporan saat ini dan file yang ditentukan untuk reportType. Ketika laporan dikirim ke jendela pesan debug, nama file, lineNumber, dan moduleName disertakan dalam informasi yang ditampilkan di jendela.

Otodidak
sumber
Ada baiknya menambahkan jawaban atau catatan yang _RPTF0dapat digunakan di mana tidak ada variabel yang diharapkan diteruskan setelah format string. The _RPTFNmakro, di sisi lain, membutuhkan setidaknya satu argumen mengikuti format string.
amn
5

Jika Anda ingin mencetak variabel desimal:

wchar_t text_buffer[20] = { 0 }; //temporary buffer
swprintf(text_buffer, _countof(text_buffer), L"%d", your.variable); // convert
OutputDebugString(text_buffer); // print
svensito
sumber
%uuntuk unsigned, %funtuk float sesuai referensi .
Laurie Stearn
4

Jika Anda perlu melihat output dari program yang ada yang banyak menggunakan printf tanpa mengubah kode (atau dengan sedikit perubahan), Anda dapat mendefinisikan ulang printf sebagai berikut dan menambahkannya ke header umum (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
sumber
1
hati-hati karena buffer statis, fungsi ini bukan reentrant dan tidak dapat digunakan dari utas yang berbeda.
Nikazo
2

Proyek Win32 Anda kemungkinan besar merupakan proyek GUI, bukan proyek konsol. Ini menyebabkan perbedaan pada header yang dapat dieksekusi. Akibatnya, proyek GUI Anda akan bertanggung jawab untuk membuka jendelanya sendiri. Itu mungkin jendela konsol. Panggil AllocConsole()untuk membuatnya, dan gunakan fungsi konsol Win32 untuk menulis padanya.

MSalters
sumber
2

Saya sedang mencari cara untuk melakukan ini sendiri dan menemukan solusi sederhana.

Saya berasumsi bahwa Anda memulai Proyek Win32 default (aplikasi Windows) di Visual Studio, yang menyediakan fungsi "WinMain". Secara default, Visual Studio menetapkan titik masuk ke "SUBSYSTEM: WINDOWS". Anda harus terlebih dahulu mengubahnya dengan membuka:

Proyek -> Properti -> Linker -> Sistem -> Subsistem

Dan pilih "Console (/ SUBSYSTEM: CONSOLE)" dari daftar drop-down.

Sekarang, program tidak akan berjalan, karena fungsi "main" dibutuhkan sebagai pengganti fungsi "WinMain".

Jadi sekarang Anda dapat menambahkan fungsi "main" seperti yang biasa Anda lakukan di C ++. Setelah ini, untuk memulai program GUI, Anda dapat memanggil fungsi "WinMain" dari dalam fungsi "utama".

Bagian awal dari program Anda sekarang akan terlihat seperti ini:

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

Hasil implementasi saya

Sekarang Anda dapat menggunakan fungsi untuk menampilkan konsol di bagian mana pun dari program GUI Anda untuk debugging atau tujuan lain.

muncul
sumber
2

Anda juga dapat menggunakan metode WriteConsole untuk mencetak di konsol.

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