Làm cách nào để in ra cửa sổ đầu ra gỡ lỗi trong ứng dụng Win32?


97

Tôi có một dự án win32 mà tôi đã tải vào Visual Studio 2005. Tôi muốn có thể in mọi thứ vào cửa sổ xuất Visual Studio, nhưng tôi không thể tìm ra cách làm trong đời. Tôi đã thử 'printf' và 'cout <<' nhưng tin nhắn của tôi vẫn không được in.

Có một số cách đặc biệt để in ra cửa sổ xuất Visual Studio không?


11
Lưu ý rằng Cửa sổ đầu ra của Visual Studio không phải là bảng điều khiển. Cả hai đều là "cửa sổ với văn bản trong đó", nhưng khác nhau ở hậu trường.
MSalters

Câu trả lời:


136

Bạn có thể sử dụng OutputDebugString. OutputDebugStringlà một macro tùy thuộc vào tùy chọn xây dựng của bạn hoặc ánh xạ tới OutputDebugStringA(char const*)hoặc OutputDebugStringW(wchar_t const*). Trong trường hợp sau, bạn sẽ phải cung cấp một chuỗi ký tự rộng cho hàm. Để tạo một ký tự rộng, bạn có thể sử dụng Ltiền tố:

OutputDebugStringW(L"My output string.");

Thông thường, bạn sẽ sử dụng phiên bản macro cùng với _Tmacro như sau:

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

Nếu dự án của bạn được định cấu hình để xây dựng cho UNICODE, dự án đó sẽ mở rộng thành:

OutputDebugStringW(L"My output string.");

Nếu bạn không xây dựng UNICODE, nó sẽ mở rộng thành:

OutputDebugStringA("My output string.");

2
Hoàn hảo! Cảm ơn. Tuy nhiên, để hoàn thiện, hóa ra tôi phải làm điều này: OutputDebugString (TEXT ("Hello console world")); .. có lẽ là do một số tùy chọn xây dựng liên quan đến unicode.
izb

1
lưu ý rằng bạn sẽ thấy hữu ích khi gỡ lỗi từ sysinternals. Điều này cho phép bạn xem các đầu ra ODS ngay cả khi Visual Studio không chạy (hoặc thậm chí cài đặt) trên hộp
pm100

4
@CDT: Còn tùy loại myStr. Là nó char*, wchar_t*hoặc LPTSTR? Giả sử rằng đó là char*bạn chỉ cần gọi OutputDebugStringA(myStr)hoặc sử dụng OutputDebugStringWvới wchar_t*OutputDebugStringvới LPTSTRnhư đã giải thích trong câu trả lời của tôi.
Martin Liversage

1
@CDT: Còn gì đơn giản hơn việc gọi một hàm có một tham số duy nhất là thông báo bạn muốn xuất ra? Nó có phải là độ phức tạp ANSI / UNICODE không? Chỉ cần sử dụng OutputDebugStringvà xác định các ký hiệu tiền xử lý thích hợp để phù hợp với độ rộng của các ký tự bạn sử dụng hoặc đi với các loại "T" linh hoạt cho phép bạn biên dịch sang cả ký tự 8 và 16 bit.
Martin Liversage

1
@MonaJalal: Qua comment của bạn không rõ là màn hình gì nên hơi khó tư vấn cụ thể cho bạn. Nếu bạn gỡ lỗi quy trình của mình, trình gỡ lỗi sẽ có cách hiển thị kết quả gỡ lỗi. Nếu bạn đang sử dụng Visual Studio làm trình gỡ lỗi, đầu ra sẽ được hiển thị trong cửa sổ Đầu ra . Để thực sự xem đầu ra, bạn phải chọn Gỡ lỗi từ Hiển thị đầu ra từ trình đơn thả xuống. Nếu vì lý do nào đó bạn đang chạy quy trình của mình bên ngoài trình gỡ lỗi, bạn có thể sử dụng DebugView để xem kết quả gỡ lỗi từ tất cả các quy trình.
Martin Liversage

29

Nếu dự án là một dự án GUI, sẽ không có bảng điều khiển nào xuất hiện. Để thay đổi dự án thành một bảng điều khiển, bạn cần vào bảng thuộc tính của dự án và đặt:

  • Trong " linker-> System-> SubSystem " giá trị " Console (/ SUBSYSTEM: CONSOLE) "
  • Trong " C / C ++ -> Tiền xử lý-> Định nghĩa tiền xử lý " thêm định nghĩa " _CONSOLE "

Giải pháp này chỉ hoạt động nếu bạn có điểm nhập " int main () " cổ điển .

Nhưng nếu bạn giống như trong trường hợp của tôi (một dự án openGL), bạn không cần phải chỉnh sửa các thuộc tính, vì điều này hoạt động tốt hơn:

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

printf và cout sẽ hoạt động như bình thường.

Nếu bạn gọi AllocConsole trước khi tạo cửa sổ, giao diện điều khiển sẽ xuất hiện phía sau cửa sổ, nếu bạn gọi nó sau, giao diện điều khiển sẽ xuất hiện phía trước.

Cập nhật

freopenkhông được dùng nữa và có thể không an toàn. Sử dụng freopen_sthay thế:

FILE* fp;

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

EDITBINcó thể đặt hệ thống con thành CONSOLEngay cả khi bạn đang sử dụng WinMainhơn là int main().
Ben Voigt

1
@Zac. Cảm ơn! 4 dòng bắt đầu bằng AllocConsole () hoạt động tốt. Cộng 1 cho điều đó. Không có gì khác đang hoạt động, mặc dù tôi đã nhận các bảng điều khiển để hiển thị trước đây trong các dự án Win32 trước khi sử dụng macro / SUBSYSTEM: CONSOLE và / hoặc _CONSOLE trước đó. Không biết tại sao macro không hoạt động tối nay. Nó có thể liên quan gì đến việc sử dụng Hỗ trợ thời gian chạy ngôn ngữ chung (/ clr) không?
riderBill

12

Để in ra realbảng điều khiển, bạn cần hiển thị nó bằng cách sử dụng cờ trình liên kết /SUBSYSTEM:CONSOLE. Cửa sổ giao diện điều khiển bổ sung gây khó chịu, nhưng đối với mục đích gỡ lỗi, nó rất có giá trị.

OutputDebugString in ra đầu ra của trình gỡ lỗi khi chạy bên trong trình gỡ lỗi.


6
Bạn cũng có thể bố trí giao diện điều khiển của riêng bạn sử dụng AllocConsole ()
Billy Oneal

4

Cân nhắc sử dụng Macro thời gian chạy VC ++ cho Báo cáo _RPT N () và _RPTF N ()

Bạn có thể sử dụng các macro _RPTn và _RPTFn, được định nghĩa trong CRTDBG.H, để thay thế việc sử dụng các câu lệnh printf để gỡ lỗi. Các macro này sẽ tự động biến mất trong bản dựng phát hành của bạn khi _DEBUG không được xác định, vì vậy không cần đặt chúng trong #ifdefs.

Thí dụ...

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

Hoặc bạn có thể sử dụng trực tiếp các hàm thời gian chạy VC ++ _CrtDbgReport, _CrtDbgReportW .

_CrtDbgReport và _CrtDbgReportW có thể gửi báo cáo gỡ lỗi đến ba điểm đến khác nhau: tệp báo cáo gỡ lỗi, trình theo dõi gỡ lỗi (trình gỡ lỗi Visual Studio) hoặc cửa sổ thông báo gỡ lỗi.

_CrtDbgReport và _CrtDbgReportW tạo thông báo người dùng cho báo cáo gỡ lỗi bằng cách thay thế đối số [n] đối số vào chuỗi định dạng, sử dụng các quy tắc tương tự được xác định bởi các hàm printf hoặc wprintf. Sau đó, các hàm này tạo báo cáo gỡ lỗi và xác định đích hoặc các điểm đến, dựa trên chế độ báo cáo hiện tại và tệp được xác định cho reportType. Khi báo cáo được gửi đến cửa sổ thông báo gỡ lỗi, tên tệp, số dòng và tên mô-đun được bao gồm trong thông tin hiển thị trong cửa sổ.


Nó đáng để thêm vào câu trả lời hoặc ghi chú _RPTF0có thể được sử dụng khi không có biến nào được mong đợi được chuyển sau chuỗi định dạng. Mặt khác _RPTFN, macro yêu cầu ít nhất một đối số theo sau chuỗi định dạng.
Amn

4

Nếu bạn muốn in các biến thập phân:

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

4

Nếu bạn cần xem đầu ra của một chương trình hiện có sử dụng rộng rãi printf w / o thay đổi mã (hoặc với những thay đổi tối thiểu), bạn có thể xác định lại printf như sau và thêm nó vào tiêu đề chung (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__)

1
hãy cẩn thận vì bộ đệm tĩnh, chức năng này không thể nhập lại và không thể được sử dụng từ các luồng khác nhau.
Nikazo

2

Dự án Win32 của bạn có thể là một dự án GUI, không phải một dự án bảng điều khiển. Điều này gây ra sự khác biệt trong tiêu đề thực thi. Do đó, dự án GUI của bạn sẽ chịu trách nhiệm mở cửa sổ của chính nó. Tuy nhiên, đó có thể là một cửa sổ giao diện điều khiển. Gọi AllocConsole()để tạo nó và sử dụng các chức năng của bảng điều khiển Win32 để ghi vào nó.


2

Tôi đang tìm cách để tự mình làm điều này và tìm ra một giải pháp đơn giản.

Tôi giả sử rằng bạn đã khởi động Dự án Win32 (ứng dụng Windows) mặc định trong Visual Studio, cung cấp chức năng "WinMain". Theo mặc định, Visual Studio đặt điểm nhập thành "SUBSYSTEM: WINDOWS". Trước tiên, bạn cần thay đổi điều này bằng cách đi tới:

Dự án -> Thuộc tính -> Trình liên kết -> Hệ thống -> Hệ thống con

Và chọn "Bảng điều khiển (/ SUBSYSTEM: CONSOLE)" từ danh sách thả xuống.

Bây giờ, chương trình sẽ không chạy, vì cần hàm "main" thay vì hàm "WinMain".

Vì vậy, bây giờ bạn có thể thêm một hàm "chính" như bạn thường làm trong C ++. Sau đó, để khởi động chương trình GUI, bạn có thể gọi hàm "WinMain" từ bên trong hàm "chính".

Phần bắt đầu của chương trình của bạn bây giờ sẽ trông giống như sau:

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

Kết quả thực hiện của tôi

Giờ đây, bạn có thể sử dụng các hàm để xuất ra bảng điều khiển trong bất kỳ phần nào của chương trình GUI để gỡ lỗi hoặc các mục đích khác.


2

Bạn cũng có thể sử dụng phương thức WriteConsole để in trên bảng điều khiển.

AllocConsole();
LPSTR lpBuff = "Hello Win32 API";
DWORD dwSize = 0;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), lpBuff, lstrlen(lpBuff), &dwSize, NULL);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.