??在Windows上使用C++写项目需要控制台显示一些信息,尤其一些GUI程序。虽然自带输出和相关调试函数,但总是不太方便,来回切挺麻烦的,这里分享一下我封装好的带有格式化输出的调试控制台供大家使用。如下是头文件:
#pragma once// 作者:WingSummer(寂静的羽夏)// 协议:MIT// 作用:对调试控制台的封装,仅限于 Windows 平台#include <Windows.h>class CDebugConsole{public: /// <summary> /// 初始化控制台,使用前必须执行 /// </summary> /// <returns>成功返回 true,失败返回 false</returns> bool static InitConsole(); /// <summary> /// 关闭控制台并释放使用的资源 /// </summary> /// <returns></returns> bool static CloseConsole(); /// <summary> /// 向控制台输出字符串信息 /// </summary> /// <param name="info">想要输出的 ASCII 字符串</param> /// <returns>成功返回 true,失败返回 false</returns> bool static Write(char* info); /// <summary> /// 向控制台输出字符串信息 /// </summary> /// <param name="info">想要输出的宽字符字符串</param> /// <returns>成功返回 true,失败返回 false</returns> bool static Write(wchar_t* info); /// <summary> /// 向控制台输出格式化字符串信息 /// </summary> /// <param name="format">待格式化的 ASCII 字符串</param> /// <param name="">格式化参数</param> /// <returns>成功返回 true,失败返回 false</returns> bool static WritePrintf(char* format, ...); /// <summary> /// 向控制台输出格式化字符串信息 /// </summary> /// <param name="format">待格式化的宽字符字符串</param> /// <param name="">格式化参数</param> /// <returns>成功返回 true,失败返回 false</returns> bool static WritePrintf(wchar_t* format, ...); /// <summary> /// 向控制台输出一行字符串信息 /// </summary> /// <param name="info">想要输出的 ASCII 字符串</param> /// <returns>成功返回 true,失败返回 false</returns> bool static WriteLine(char* info); /// <summary> /// 向控制台输出一行字符串信息 /// </summary> /// <param name="info">想要输出的宽字符字符串</param> /// <returns>成功返回 true,失败返回 false</returns> bool static WriteLine(wchar_t* info = L""); /// <summary> /// 向控制台输出一行格式化字符串信息 /// </summary> /// <param name="format">待格式化的 ASCII 字符串</param> /// <param name="">成功返回 true,失败返回 false</param> /// <returns></returns> bool static WritePrintfLine(char* format, ...); /// <summary> /// 向控制台输出一行格式化字符串信息 /// </summary> /// <param name="format">待格式化的宽字符字符串</param> /// <param name="">格式化参数</param> /// <returns>成功返回 true,失败返回 false</returns> bool static WritePrintfLine(wchar_t* format, ...); /// <summary> /// 设置控制台置顶,只在初始化成功控制台有效 /// </summary> /// <param name="topmost">true 则为设置置顶,反之取消</param> void static SetTopMost(bool topmost);};??如下是函数实现:
// 作者:WingSummer(寂静的羽夏)// 协议:MIT// 作用:对调试控制台的封装,仅限于 Windows 平台#include "pch.h" //这个是预编译头,如果代码项目没有就删掉#include "CDebugConsole.h"#include <stdarg.h>#define CharBufferSize 4096#define WCharBufferSize 2048#pragma warning(disable : 4267)static HANDLE handle;static void* buffer = NULL;HWND console;bool CDebugConsole::InitConsole(){ if (handle) return false; bool status = AllocConsole(); handle = GetStdHandle(STD_OUTPUT_HANDLE); console = GetConsoleWindow(); SetWindowTextW(console, L"调试输出控制台"); HMENU menu = GetSystemMenu(console, NULL); RemoveMenu(menu, SC_CLOSE, NULL); //申请分配一个物理页,我不信你的字符串会长于2047个 buffer = VirtualAlloc(NULL, CharBufferSize, MEM_COMMIT, PAGE_READWRITE); return status;}bool CDebugConsole::CloseConsole(){ if (buffer) VirtualFree(buffer, NULL, MEM_FREE); bool status = FreeConsole(); handle = NULL; console = NULL; return status;}bool CDebugConsole::Write(char* info){ if (!handle) return false; return WriteConsoleA(handle, info, strlen(info), NULL, NULL);}bool CDebugConsole::Write(wchar_t* info){ if (!handle) return false; return WriteConsoleW(handle, info, wcslen(info), NULL, NULL);}bool CDebugConsole::WritePrintf(char* format, ...){ va_list ap; va_start(ap, format); int outcount = _vsnprintf_s((char*)buffer, CharBufferSize, CharBufferSize, format, ap); if (outcount < 0 || outcount > CharBufferSize) return false; bool status = WriteConsoleA(handle, buffer, outcount, NULL, NULL); va_end(ap); return status;}bool CDebugConsole::WritePrintf(wchar_t* format, ...){ va_list ap; va_start(ap, format); int outcount = _vsnwprintf_s((wchar_t*)buffer, WCharBufferSize, WCharBufferSize, format, ap); if (outcount < 0 || outcount > WCharBufferSize) return false; bool status = WriteConsoleW(handle, buffer, outcount, NULL, NULL); va_end(ap); return status;}bool CDebugConsole::WriteLine(char* info){ size_t len = strlen(info); if (len + 1 > CharBufferSize) { return false; } memcpy_s(buffer, CharBufferSize, info, len); char* p = (char*)buffer; p[len] = '\n'; return WriteConsoleA(handle, buffer, len + 1, NULL, NULL);}bool CDebugConsole::WriteLine(wchar_t* info){ size_t len = wcslen(info); if (len + 1 > WCharBufferSize) { return false; } memcpy_s(buffer, CharBufferSize, info, len * 2); wchar_t* p = (wchar_t*)buffer; p[len] = '\n'; return WriteConsoleW(handle, buffer, len + 1, NULL, NULL);}bool CDebugConsole::WritePrintfLine(char* format, ...){ va_list ap; va_start(ap, format); int outcount = _vsnprintf_s((char*)buffer, CharBufferSize, CharBufferSize, format, ap); if (outcount < 0 || outcount > CharBufferSize - 1) return false; char* p = (char*)buffer; p[outcount] = '\n'; bool status = WriteConsoleA(handle, buffer, outcount + 1, NULL, NULL); va_end(ap); return status;}bool CDebugConsole::WritePrintfLine(wchar_t* format, ...){ va_list ap; va_start(ap, format); int outcount = _vsnwprintf_s((wchar_t*)buffer, WCharBufferSize, WCharBufferSize, format, ap); if (outcount < 0 || outcount > WCharBufferSize - 1) return false; wchar_t* p = (wchar_t*)buffer; p[outcount] = '\n'; bool status = WriteConsoleW(handle, buffer, outcount + 1, NULL, NULL); va_end(ap); return status;}void CDebugConsole::SetTopMost(bool topmost){ if (!console) return; SetWindowPos(console, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);}??注意,由于里面使用了WinAPI进行封装,故 只能在Windows上 使用。使用上述代码时,请保留我的个人信息。
??这个实现的原理并不难,代码也通俗易懂,使用函数接口注释比较详尽。对于C#版本本人暂时无法写,由于PInvoke无法调用WriteConsole函数,故本人无法封装。如果仍想使用,可以只封装我代码中的初始化控制台和关闭控制台以及Write函数即可,生成Dll,再PInvoke,因为C#的字符串处理和格式化十分的方便,没必要写。希望以上代码对你有帮助。如下是效果:

