向Win32 GUI程序添加控制I/O

最近使用D3D11做开小车的网易-1任务, 程序的入口函数是WinMain函数, 无法使用cout进行调试, 蓝瘦香菇, 使用常规的项目属性-配置属性-链接器-系统-子系统-控制台大法依旧无果, 终于在stackoverflow觅得良方, 撒花✿✿ヽ(°▽°)ノ✿

参考材料
1. How do I get console output in C++ with a Windows program?
2. winmain和main入口函数比较

需要进行重定向, 虽然我也不大懂代码具体写了啥, 囧…… 反正能用就行, 管它咧233333

#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG

#include <iostream>

void RedirectIOToConsole();

#endif
#endif

// End of File
#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <fstream>
#include <guicon.h>
#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
// maximum mumber of lines the output console should have
static const WORD MAX_CONSOLE_LINES = 500;
#ifdef _DEBUG
void RedirectIOToConsole()
{
	int hConHandle;
	long lStdHandle;
	CONSOLE_SCREEN_BUFFER_INFO coninfo;
	FILE *fp;

	// allocate a console for this app
	AllocConsole();

	// set the screen buffer to be big enough to let us scroll text
	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
	coninfo.dwSize.Y = MAX_CONSOLE_LINES;
	SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);

	// redirect unbuffered STDOUT to the console
	lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "w");
	*stdout = *fp;
	setvbuf(stdout, NULL, _IONBF, 0);

	// redirect unbuffered STDIN to the console
	lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "r");
	*stdin = *fp;
	setvbuf(stdin, NULL, _IONBF, 0);

	// redirect unbuffered STDERR to the console
	lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen(hConHandle, "w");
	*stderr = *fp;
	setvbuf(stderr, NULL, _IONBF, 0);

	// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
	// point to console as well
	ios::sync_with_stdio();

	// Get STDOUT handle
	HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	int SystemOutput = _open_osfhandle(intptr_t(ConsoleOutput), _O_TEXT);
	FILE *COutputHandle = _fdopen(SystemOutput, "w");

	// Get STDERR handle
	HANDLE ConsoleError = GetStdHandle(STD_ERROR_HANDLE);
	int SystemError = _open_osfhandle(intptr_t(ConsoleError), _O_TEXT);
	FILE *CErrorHandle = _fdopen(SystemError, "w");

	// Get STDIN handle
	HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
	int SystemInput = _open_osfhandle(intptr_t(ConsoleInput), _O_TEXT);
	FILE *CInputHandle = _fdopen(SystemInput, "r");

	//make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
	ios::sync_with_stdio(true);

	// Redirect the CRT standard input, output, and error handles to the console
	freopen_s(&CInputHandle, "CONIN$", "r", stdin);
	freopen_s(&COutputHandle, "CONOUT$", "w", stdout);
	freopen_s(&CErrorHandle, "CONOUT$", "w", stderr);

	//Clear the error state for each of the C++ standard stream objects. We need to do this, as
	//attempts to access the standard streams before they refer to a valid target will cause the
	//iostream objects to enter an error state. In versions of Visual Studio after 2005, this seems
	//to always occur during startup regardless of whether anything has been read from or written to
	//the console or not.
	std::wcout.clear();
	std::cout.clear();
	std::wcerr.clear();
	std::cerr.clear();
	std::wcin.clear();
	std::cin.clear();
}

#endif
//End of File
#include "guicon.h"

int WINAPI WinMain(HINSTANCE hinstance,
	HINSTANCE prevInstance,
	PSTR cmdLine,
	int showCmd)
{
#ifdef _DEBUG
	RedirectIOToConsole();
#endif

        std::cout<<"test"<<std::endl;
}

注记1: WinMain函数接收4个参数, 这些参数都是在系统调用WinMain函数时, 传递给应用程序的.
第一个参数hInstance表示该程序当前运行的实例的句柄, 这是一个数值. 当程序在Windows下运行时, 它唯一标识运行中的实例(注意, 只有运行中的程序实例, 才有实例句柄), 一个应用程序可以运行多个实例, 每运行一个实例, 系统都会给该实例分配一个句柄值, 并通过hInstance参数传递给WinMain函数.
第二个参数hPrevInstance(MSDN) 在Win32环境下, 这个参数不起作用, 历史遗留, hPrevInstance=NULL.
第三个参数lpCmdLine是一个以空(‘\0’) 终止的字符串, 指定传递给应用程序的命令行参数.

注记2: 运行参数, 例如在命令行键入: test.exe /install, 那么程序入口WinMain处, 其参数lpCmdLine就接收到了/install参数. 但是, 至于你用这个参数做什么, 那是用代码实现. 而实现安装, 这需要根据你的需求加入代码, 和命令行参数无关. 这个跟命令行的int main(int argc, char* argv[])不同.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注