如標題所述,我想使用命令列控制臺撰寫游戲引擎。緊跟oneLoneCoder的專案,目前我寫的代碼如下。在檢查用戶提供的尺寸是否正確后,它會創建一個命令控制臺。
#include <Windows.h>
#include <iostream>
#include <cassert>
namespace CmdLineConsoleEngine {
void Error(const HANDLE& hConsole, const wchar_t* msg) {
wchar_t buf[256];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
SetConsoleActiveScreenBuffer(hConsole);
wprintf(L"ERROR: %s\n\t%s\n", msg, buf);
exit(-1);
}
auto CreateConsole() -> HANDLE {
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
if (hConsole == INVALID_HANDLE_VALUE)
Error(hConsole, L"Bad Handle"); // in which cases does this occur?
else {
SetConsoleActiveScreenBuffer(hConsole);
}
return hConsole;
}
void CheckConsoleSize(const HANDLE& hConsole, int screenWidth, int screenHeight) {
assert(hConsole != nullptr);
assert(screenWidth > 0);
assert(screenHeight > 0);
const COORD largestSize = GetLargestConsoleWindowSize(hConsole);
if (screenWidth > largestSize.X)
Error(hConsole, L"The width dimension is too large.");
if (screenHeight > largestSize.Y)
Error(hConsole, L"The height dimension is too large.");
return;
}
void SetConsoleWindowSize(HANDLE& hConsole, int screenWidth, int screenHeight) {
CheckConsoleSize(hConsole, screenWidth, screenHeight);
const SMALL_RECT minimalRectWindow = { 0, 0, 12, 6 };
SetConsoleWindowInfo(hConsole, TRUE, &minimalRectWindow);
COORD coord = {static_cast<short>(screenWidth), static_cast<short>(screenHeight)};
if (!SetConsoleScreenBufferSize(hConsole, coord))
Error(hConsole, L"SetConsoleScreenBufferSize");
SMALL_RECT rectWindow = {0, 0, static_cast<short>(screenWidth - 1), static_cast<short>(screenHeight - 1)};
if (!SetConsoleWindowInfo(hConsole, TRUE, &rectWindow))
Error(hConsole, L"SetConsoleWindowInfo");
return;
}
void WriteToConsole(const HANDLE& hConsole, const wchar_t* screen, int screenWidth, int screenHeight) {
DWORD dwBytesWritten = 0;
WriteConsoleOutputCharacter(hConsole, screen, screenWidth * screenHeight, { 0,0 }, &dwBytesWritten);
}
}
int main() {
HANDLE hConsole = CmdLineConsoleEngine::CreateConsole();
int screenWidth = 160;
int screenHeight = 140;
CmdLineConsoleEngine::SetConsoleWindowSize(hConsole, screenWidth, screenHeight);
return 0;
}
執行main()函式,我得到的輸出是
ERROR: The height dimension is too large.
The operation completed successfully.
它是一個Error有趣的功能。為方便起見,呼叫層次結構是SetConsoleWindowSize -> CheckConsoleSize -> Error
關于為什么會發生這種情況的任何想法?
uj5u.com熱心網友回復:
你的錯誤報告CheckConsoleSize()是錯誤的。GetLastError()僅當GetLargestConsoleWindowSize()回傳COORD包含所有零的a時才有意義,您沒有檢查它。您所描述的內容聽起來像是COORD只包含比您預期的要小的尺寸,但不是零。這就是為什么GetLastError()回傳 0,因此FormatMessage()回傳"The operation completed successfully"。
嘗試更像這樣的事情:
#include <Windows.h>
#include <iostream>
#include <cassert>
namespace CmdLineConsoleEngine {
void Error(HANDLE hConsole, const wchar_t* msg) {
SetConsoleActiveScreenBuffer(hConsole);
wprintf(L"ERROR: %s\n", msg);
exit(-1);
}
void ErrorWithCode(HANDLE hConsole, const wchar_t* msg, DWORD ErrorCode = GetLastError()) {
wchar_t buf[256] = {};
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
SetConsoleActiveScreenBuffer(hConsole);
wprintf(L"ERROR: %s\n\t%s\n", msg, buf);
exit(-1);
}
HANDLE CreateConsole() {
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
if (hConsole == INVALID_HANDLE_VALUE)
ErrorWithCode(hConsole, L"Bad Handle"); // in which cases does this occur?
SetConsoleActiveScreenBuffer(hConsole);
return hConsole;
}
void DestroyConsole(HANDLE& hConsole) {
if (hConsole != INVALID_HANDLE_VALUE) {
CloseHandle(hConsole);
hConsole = INVALID_HANDLE_VALUE;
}
}
void CheckConsoleSize(HANDLE hConsole, int screenWidth, int screenHeight) {
assert(hConsole != INVALID_HANDLE_VALUE);
assert(screenWidth > 0);
assert(screenHeight > 0);
const COORD largestSize = GetLargestConsoleWindowSize(hConsole);
if (largestSize.X == 0 && largestSize.Y == 0)
ErrorWithCode(hConsole, L"GetLargestConsoleWindowSize");
if (screenWidth > largestSize.X)
Error(hConsole, L"The width dimension is too large.");
if (screenHeight > largestSize.Y)
Error(hConsole, L"The height dimension is too large.");
}
void SetConsoleWindowSize(HANDLE hConsole, int screenWidth, int screenHeight) {
CheckConsoleSize(hConsole, screenWidth, screenHeight);
const SMALL_RECT minimalRectWindow = { 0, 0, 12, 6 };
if (!SetConsoleWindowInfo(hConsole, TRUE, &minimalRectWindow))
ErrorWithCode(hConsole, L"SetConsoleWindowInfo");
COORD coord = {static_cast<short>(screenWidth), static_cast<short>(screenHeight)};
if (!SetConsoleScreenBufferSize(hConsole, coord))
ErrorWithCode(hConsole, L"SetConsoleScreenBufferSize");
SMALL_RECT rectWindow = {0, 0, static_cast<short>(screenWidth - 1), static_cast<short>(screenHeight - 1)};
if (!SetConsoleWindowInfo(hConsole, TRUE, &rectWindow))
ErrorWithCode(hConsole, L"SetConsoleWindowInfo");
}
void WriteToConsole(HANDLE hConsole, const wchar_t* screen, int screenWidth, int screenHeight) {
DWORD dwBytesWritten = 0;
if (!WriteConsoleOutputCharacter(hConsole, screen, screenWidth * screenHeight, {0, 0}, &dwBytesWritten))
ErrorWithCode(hConsole, L"WriteConsoleOutputCharacter");
}
}
int main() {
HANDLE hConsole = CmdLineConsoleEngine::CreateConsole();
CmdLineConsoleEngine::SetConsoleWindowSize(hConsole, 160, 140);
CmdLineConsoleEngine::DestroyConsole(hConsole);
return 0;
}
附帶說明:Error/WithCode()如果CreateConsoleScreenBuffer()失敗則呼叫沒有意義,因為您將SetConsoleActiveScreenBuffer()使用無效的控制臺句柄進行呼叫。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/344022.html
