I am experiencing trouble when attempting to output to a region within the top right corner of a console window. I am working within an 80x20 region, and am attempting to update a small region (16x3) in the corner with essential information to a user. However, I keep receiving error code 87 from GetLastError() as the WriteConsoleOutputW() function is returning 0 for some strange reason.
I have ensured that the size of the region's buffer is correct using a COORD object COORD{16, 3}, that the buffer's size is correctly CHAR_INFO diagBoxBuffer[48], and that the SMALL_RECT object is correctly constructed (the upper-left and bottom-right corners of the rectangle to write to) SMALL_RECT{64, 0, 79, 2}.
So, given that these parameters are what I assume to be correct, based on my readings from the Console's API docs, I seem to be unable to decipher the issue here. I have experimented with different assignments to the CHAR_INFO buffer, such as assigning a simple character to the first element and testing output, but no success, only the odd crash or an output of error code 87.
Here is what I am experimenting with (is a separate screen buffer needed? I will try this next):
if(!WriteConsoleOutputW(hStdOut, diagBoxBuffer, diagnosticBoxSize, cursordiagnosticBoxStart, &diagBox))
{
wcout << L"WriteConsoleOutputW failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
And here is some extra data declared earlier:
(diagBoxBuffer[0]).Char.UnicodeChar = L'H';
(diagBoxBuffer[5]).Char.UnicodeChar = L'W';
(diagBoxBuffer[11]).Char.UnicodeChar = L'C';
(diagBoxBuffer[4]).Char.UnicodeChar = L'|';
(diagBoxBuffer[9]).Char.UnicodeChar = L'|';
(diagBoxBuffer[10]).Char.UnicodeChar = L'|';
(diagBoxBuffer[16]).Char.UnicodeChar = L'W';
(diagBoxBuffer[17]).Char.UnicodeChar = L':';
/* Some functionality needs to be implemented here for the behavior of [17] and [18]. */
(diagBoxBuffer[35]).Char.UnicodeChar = L'|';
(diagBoxBuffer[41]).Char.UnicodeChar = L'|';
And globally:
COORD sbSize{80, 20};
/* The screen buffer for consoleRPG should be 80 character cells by 20 character cells. */
COORD diagnosticBoxSize{16, 3};
COORD cursorHome{0, 0};
/* For setting the cursor at its default position. Other positions may become necessary as the program grows. */
COORD cursordiagnosticBoxStart{64, 0};
/* A diagnostic box of 15x3 characters should be plenty, ranging from [65:79) on rows [0:2). */
COORD cursordiagnosticBoxFinish{79, 2};
SMALL_RECT consoleCoords{0, 0, 79, 19}; /* This should supply the main area for console operations. */
SMALL_RECT diagBox{64, 0, 79, 2}; /* This should supply a simple area to write to for input or coordinates, and could serve as map info later. */
hStdOut is assigned to STD_OUTPUT_HANDLE.
I assume that the STD_OUTPUT_HANDLE should be fine for writing to, but I suppose I will have to try another screen buffer to see if that solves the issue.
Here is a reproducible example, at the request of #RetiredNinja:
#define UNICODE
#include <Windows.h>
#include <WinUser.h>
#include <iostream> /* A console application should automatically initialize a console with default handles (STDIN, STDOUT, STDERROR). */
#include <bitset>
#pragma comment(lib, "User32.lib")
using namespace std;
COORD sbSize{80, 20}; /* The screen buffer for consoleRPG should be 80 character cells by 20 character cells. */
COORD diagnosticBoxSize{16, 3};
COORD cursorHome{0, 0}; /* For setting the cursor at its default position. Other positions may become necessary as the program grows. */
COORD cursordiagnosticBoxStart{64, 0}; /* A diagnostic box of 15x3 characters should be plenty, ranging from [65:79) on rows [0:2). */
COORD cursordiagnosticBoxFinish{79, 2};
SMALL_RECT consoleCoords{0, 0, 79, 19}; /* This should supply the main area for console operations. */
SMALL_RECT diagBox{64, 0, 79, 2}; /* This should supply a simple area to write to for input or coordinates, and could serve as map info later. */
CONSOLE_SCREEN_BUFFER_INFO consoleInfo{};
void clearConsole(HANDLE);
void cursorReset();
void writeDiagnostic(HANDLE, const int=0);
/* A value can be supplied here to output input records (default, 0) or error info (bad option, etc.). */
CHAR_INFO outputBuffer[80];
CHAR_INFO inputBuffer[80];
CHAR_INFO diagBoxBuffer[48];
CHAR_INFO diagnosticBoxTextGreen{L' ', FOREGROUND_GREEN};
wchar_t outputBufferW[80];
wchar_t desktop[] = L"consoleRPG";
wchar_t cmdpath[] = L"C:\\Windows\\System32\\cmd.exe";
int main() /* We want to create the basic start for consoleRPG as well as implement a small 15x3 diagnostic box in the top right corner. */
{
HWND consoleWindow = GetConsoleWindow();
HANDLE hNewProcess;
HANDLE hNewThread;
HANDLE hStdOut;
HANDLE hStdIn;
HANDLE hStdErr;
STARTUPINFOW newConsole{
1024,
NULL,
NULL,
NULL,
0,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
STARTF_USEPOSITION | STARTF_USESIZE | STARTF_USECOUNTCHARS | STARTF_USESTDHANDLES,
NULL,
0,
0,
NULL,
NULL,
NULL
};
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
CONSOLE_CURSOR_INFO StdCursorInfo{100, 1};
SetConsoleCursorInfo(hStdOut, &StdCursorInfo);
PROCESS_INFORMATION newProcess{};
DWORD processID = 0;
DWORD threadID = 0;
if(!CreateProcessW(
cmdpath,
NULL,
NULL,
NULL,
FALSE,
CREATE_UNICODE_ENVIRONMENT, /* dwCreationFlags - this is possibly unneeded. */
NULL,
NULL,
&newConsole,
&newProcess
)
)
{
wcout << L"CreateProcess failed. Error Code: " << GetLastError();
system("pause");
return 0;
}
if(!SetConsoleTitle(desktop))
{
wcout << L"SetConsoleTitle failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
if(!SetConsoleWindowInfo(hStdOut, TRUE, &consoleCoords))
{
wcout << L"SetConsoleWindowInfo failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
if(!SetConsoleScreenBufferSize(hStdOut, sbSize))
{
wcout << L"SetConsoleScreenBufferSize failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
SetLastError(0);
LONG_PTR windowStyle = GetWindowLongPtrW(consoleWindow, GWL_STYLE);
if(windowStyle == 0)
{
wcout << L"GetWindowLongPtrW failed. Error code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
if(SetWindowLongPtrW(consoleWindow, GWL_STYLE, windowStyle & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX) == 0 && GetLastError()!= 0)
{
wcout << L"SetWindowLongPtrW failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
if(!SetWindowPos(consoleWindow, HWND_TOP, 325, 200, 640, 240, SWP_NOSIZE))
/* This successfully makes the window non-adjustable and unable to be maximized. */
{
wcout << L"SetWindowPos failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
system("pause");
if(!GetConsoleScreenBufferInfo(hStdOut, &consoleInfo)) /* stdConsoleInfo will be written to. */
{
wcout << L"GetConsoleScreenBufferInfo failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
}
wcout << L"sizeX: " << consoleInfo.dwSize.X << L" " << L"sizeY: " << consoleInfo.dwSize.Y << L"||" << L"cursorPosX: " <<
consoleInfo.dwCursorPosition.X << L' ' << L"cursorPosY: " << consoleInfo.dwCursorPosition.Y << L'\n' <<
L"charAttributes: " << bitset<8>{consoleInfo.wAttributes} << L'\n' << L'\n' <<
L"upperLeftX: " << consoleInfo.srWindow.Left << L" " << L"upperLeftY: " << consoleInfo.srWindow.Top << L" "
<< L"bottomRightX: " << consoleInfo.srWindow.Right << L" " << L"bottomRightY: " << consoleInfo.srWindow.Bottom << L'\n'
<< L"Rows(0-based): " << abs(consoleInfo.srWindow.Top - consoleInfo.srWindow.Bottom) << L'\t' << L"Columns(0-based): " << abs(consoleInfo.srWindow.Right - consoleInfo.srWindow.Left) << L'\n';
system("pause");
/*
Now, the console is ready for some simple formatting to prepare us for the idea of a game: functions are to be written that will process basic text. Some 48 character cells (16x3) in the upper right should be dedicated to things like the display of Health, Currency, and Location. For now Health will be a simple number.
OOOOOOOOOOOOOOOO <- Health and Weapon and Currency can go on this top row. The important statistics are shown first.
OOOOOOOOOOOOOOOO <- Weapon(?), Cargo(?), FullCargo(?) can go on this middle row.
OOOOOOOOOOOOOOOO <-- Location and time information can go on this last row.
Because space is limited for this simple consoleRPG, we must use abbreviation and symbols to display necessary information.
For the top row we can use three four-letter symbols, separated by a single pipe and a double pipe. For example: H054|W010||C0090
For the second row we will display our weight for now. For example: "W: 3/10" (The large amount of space allows us to take advantage of
great weights.) If a horse, or a carriage, etc. is in one's possession, weight will be displayed as W!.
The third row will display a three-letter symbol for a town or location followed by the time of day and the date. Useful.
Example: "SEN|NIGHT|23 CAL"
So, something we can expect for an adventurer in the middle of the game would be something like this: H054|W036||C0090
W: 3/10
SEN|NIGHT|23 CAL
*/
clearConsole(hStdOut);
/*
Pre set-up has been completed and output, and it is now time to begin outputting the basic game data. We need a way to format the 48 character
buffer that will display essential information.
So, diagBoxBuffer will need to have static characters in place at certain elements:
[0] will need to remain 'H', [5] will need to remain 'W', [11] will need to remain 'C'
[4], [9] and [10] will need to remain '|'
[16] will need to remain 'W', [17] will need to remain ':' or '!' if a horse is owned, allowing [18] to display ':'
[35] and [41] will need to remain '|'
Now, how can I ensure that numbers are displayed correctly after their symbols, i.e. prefixed by a 0? We may have to display blanks instead.
I assume I could use string-to-integer, stoi() to communicate from the diagnostic menu to the game functionality.
stoi(s) simply converts a wstring to an integer. stoi(s,p) will relay the number of characters used in the conversion of s to an integer to the element contained at p.
For communication from the game functionality to the diagnostic menu, to_wstring(x) can be used.
A prefixed 0 or blank can be prefixed to the returned string if it only contains 2 characters. Accommodations must be made to ensure that the string is displayed as characters only, without a 0 suffixed to its end.
*/
(diagBoxBuffer[0]).Char.UnicodeChar = L'H';
(diagBoxBuffer[5]).Char.UnicodeChar = L'W';
(diagBoxBuffer[11]).Char.UnicodeChar = L'C';
(diagBoxBuffer[4]).Char.UnicodeChar = L'|';
(diagBoxBuffer[9]).Char.UnicodeChar = L'|';
(diagBoxBuffer[10]).Char.UnicodeChar = L'|';
(diagBoxBuffer[16]).Char.UnicodeChar = L'W';
(diagBoxBuffer[17]).Char.UnicodeChar = L':'; /* Some functionality needs to be implemented here for the behavior of [17] and [18]. */
(diagBoxBuffer[35]).Char.UnicodeChar = L'|';
(diagBoxBuffer[41]).Char.UnicodeChar = L'|';
for(size_t i{}; i<80; ++i)
{
if((diagBoxBuffer[i]).Char.UnicodeChar == L'H'){continue;}
if((diagBoxBuffer[i]).Char.UnicodeChar == L'W'){continue;}
if((diagBoxBuffer[i]).Char.UnicodeChar == L'C'){continue;}
if((diagBoxBuffer[i]).Char.UnicodeChar == L'|'){continue;}
if((diagBoxBuffer[i]).Char.UnicodeChar == L':'){continue;}
(diagBoxBuffer[i]).Char.UnicodeChar = L' ';
}
wcout << L"diagBoxBuffer written to\n";
system("pause");
clearConsole(hStdOut);
//if(!WriteConsoleOutputW(hStdOut, &diagBoxBuffer[0], diagnosticBoxSize, cursordiagnosticBoxStart, &diagBox))
if(!WriteConsoleOutputW(hStdOut, diagBoxBuffer, diagnosticBoxSize, cursordiagnosticBoxStart, &diagBox))
{
wcout << L"WriteConsoleOutputW failed. Error Code: " << GetLastError() << L'\n';
system("pause");
return 0;
} /* Program crashes here without any error code reported. */
while(1)
{
}
return 0;
}
void clearConsole(HANDLE screen)
{
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
DWORD dwConsoleSz;
if(!GetConsoleScreenBufferInfo(screen, &bufferInfo))
{
return;
}
dwConsoleSz = bufferInfo.dwSize.X * bufferInfo.dwSize.Y; /* X (character cells) * Y (character cells) */
/* Now we fill the entire screen with blanks. */
if(!FillConsoleOutputCharacter(
screen,
L' ',
dwConsoleSz,
cursorHome,
&cCharsWritten
)
)
{
return;
}
/* Then we get the current text attribute (maybe unnecessary?) */
if(!GetConsoleScreenBufferInfo(screen, &bufferInfo)) /* Perhaps the ScreenBuffer needs to be set again, see SetConsoleCursorPosition. */
{
return;
}
/* And set the buffer's attributes accordingly. */
if(!FillConsoleOutputAttribute(
screen,
bufferInfo.wAttributes,
dwConsoleSz,
cursorHome,
&cCharsWritten
)
)
{
return;
}
if(!SetConsoleCursorPosition(screen, cursorHome))
/*Research is needed regarding this function as it does not seem to move the cursor. */
{
wcout << L"SetConsoleCursorPosition failed. Error Code: " << GetLastError();
system("pause");
}
return;
}
void cursorReset()
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorHome);
return;
}
void cursorDiagBox()
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursordiagnosticBoxStart);
return;
}
Edited: The top right corner is where I am attempting to write to.
Edit 2: I have found some success in using WriteConsoleOutputCharacterW, but not WriteConsoleOutputW. It would be more simple to use the latter; for now I return to experimentation.
According to the Doc: WriteConsoleOutput function
A rectangle of the same size is located with its upper-left cell at
the coordinates of the dwBufferCoord parameter in the lpBuffer array.
As far as I'm concerned, dwBufferCoord.Y< dwBufferSize.Y ; dwBufferCoord.X<dwBufferSize.X
cursordiagnosticBoxStart.X<16
cursordiagnosticBoxStart.Y<3
My application needs to listen to clipboard changes to record them. I can currently achieve that with a signal_owner_change callback which then requests the contents of the clipboard. However, I need to figure out which window the event originated from, so that I can ignore when a user copies text from the application itself (using Ctrl+C, not programmatically).
The signal_owner_change callback takes a GdkEventOwnerChange* as a parameter, which contains the fields owner and window of type GdkWindow*.
The field owner changes for each different application / window I copy from, but never corresponds to the window pointer of my application.
The field window is always the same, but also does not match my application window.
Unfortunately, the GTK+ documentation is very unclear about what the "owner" and the "window" of a GdkEventOwnerChange is, or how to exploit the data.
My application window is a class inheriting from Gtk::ApplicationWindow. I get the GdkWindow* as such:
GdkWindow* win = gtk_widget_get_window(GTK_WIDGET(gobj()));
Here is an extract of the clipboard owner change even handler: (in another class, which gets the window pointer above as parentWindow)
MyNamespace::MyClass::MyClass(GdkWindow* parentWindow)
: parentWindow(parentWindow) {
// setup UI, etc...
clipboard = Gtk::Clipboard::get();
clipboard->signal_owner_change().connect(
sigc::mem_fun(*this, &MyClass::on_clipboard_owner_change));
}
void MyNamespace::MyClass::on_clipboard_owner_change(GdkEventOwnerChange* event) {
std::cout << "Owner: " << event->owner
<< ", window: " << event->window
<< ", parent: " << parentWindow
<< std::endl;
// This does not work
if (event->owner == parentWindow)
return;
switch (get_clipboard_content_type()) {
case ClipboardDataType::Text: {
clipboard->request_text(
sigc::mem_fun(*this, &MyClass::on_clipboard_text_received));
break;
}
case ClipboardDataType::Image: {
std::cout << "Image is available, unimplemented handler" << std::endl;
break;
}
case ClipboardDataType::URIs: {
std::cout << "URIs is available, unimplemented handler" << std::endl;
break;
}
default: {
std::cout << "Unknown or unsupported clipboard data type" << std::endl;
}
}
}
Here is the console output:
# Copy from another application
Owner: 0x5571ec44dc80, window: 0x5571ec08f330, parent: 0x5571ec08f4c0
# Copy from the application itself
Owner: 0x5571ec44de10, window: 0x5571ec08f330, parent: 0x5571ec08f4c0
I have tried comparing with the Gtk::Application toplevel window, or with the window of the Gtk::Label (label->get_window()->gobj()) that gets copied but none of the pointers match.
I'm trying to add GUI for easier level editing in our game engine. We're using SFML for all the basic stuff (window management, input events etc). I've chosen AntTweakBar because it is a well known library with a few examples around. I was following the tutorial at AntTweakBar's website
I was able to draw a simple bar with those example codes. However, mouse events received by SFML are not registered by AntTweakBar's TwEventSDL()function. Here is an example code for Input:
sf::Event event;
while (_pWindow->pollEvent(event))
{
// Check if the event should be handled by AntTweakBar
int handled = TwEventSFML(&event, 2, 3); // for SFML version 2.3
if (!handled){
switch (event.type)
{
case sf::Event::MouseButtonPressed: // To check whether SFML received mouse button events properly
if (event.mouseButton.button == sf::Mouse::Button::Left){
std::cout << "Left button pressed" << std::endl;
std::cout << "x: " << event.mouseButton.x << std::endl;
std::cout << "y: " << event.mouseButton.y << std::endl;
}
}
}
else{ //To check whether TwEventSFML received events
std::cout << "FINALLY!" << std::endl;
}
When I press buttons, I can see "FINALLY!" showing up. I can also see that my mouse clicks are received by SFML. However, when I click on an AntTweakBar element (be it a button or help section) it doesn't register it. (Also, I can't see "FINALLY!" when I use the mouse).
Any help or ideas will be appreciated.
Anttweakbar hasnt been updated in 3 years, last SFML integration was for SFML 1.6
What version of SFML are you using ?
If not 1.6 then you have to create your own input handler for it.
When I do a get GetWindowPlacement, the WINDOWPLACEMENT::showCmd seems to be always 1, which is SW_SHOWNORMAL.
Does anyone know why is this so and if it is updated? Does anyone know if this variable is maintained by the application itself or by the operating system?
I am running this on Windows 7.
I am using this to achieve the same purpose as mentioned in this thread: I am trying to undo hidden windows that were previously shown without storing the hidden windows in memory (hide/show will be called in different run sessions) or on disk.
void hide(const unsigned int pid){
std::list<HWND> windowList = getWindowbyPID(pid);
for(std::list<HWND>::iterator it = windowList.begin(); it != windowList.end(); it++){
if(IsWindowVisible(*it)){ std::cout << "Hid WIN#" << *it << std::endl; ShowWindow(*it,SW_HIDE); }
}
}
void show(const unsigned int pid){
std::list<HWND> windowList = getWindowbyPID(pid);
for(std::list<HWND>::iterator it = windowList.begin(); it != windowList.end(); it++){
//if(IsWindowVisible(*it)){ ShowWindow(*it,SW_SHOW); }
WINDOWPLACEMENT wp;
wp.length = sizeof(wp);
wp.showCmd = 0; // Just to clear showCmd before reading.
std::cout << *it << std::endl;
std::cout << "BEFORE: " << wp.showCmd << std::endl;
GetWindowPlacement(*it,&wp);
std::cout << "AFTER: " << wp.showCmd << std::endl;
}
}
Output of one example that I did (pid of notepad.exe) after hiding hwnd#00060CD0:
003D0642
BEFORE: 0
AFTER: 1
000B0682
BEFORE: 0
AFTER: 1
00060CD0
BEFORE: 0
AFTER: 1
I am trying to use GetWindowPlacement to differentiate the windows that were always hidden and the windows that were previously shown. It never seems to be 0 even for windows that were always hidden.
There are only three possible values of the showCmd after calling GetWindowPlacement.
From the MSDN documentation on GetWindowPlacement (emphasis mine):
The flags member of WINDOWPLACEMENT retrieved by this function is always zero. If the window identified by the hWnd parameter is maximized, the showCmd member is SW_SHOWMAXIMIZED. If the window is minimized, showCmd is SW_SHOWMINIMIZED. Otherwise, it is SW_SHOWNORMAL.
Therefore, it appears that the window you're asking for placement info on is in a state other than maximized or minimized when you're calling GetWindowPlacement.
I'd suspect what you're actually looking for is IsWindowVisible.
I'm playing with QtGStreamer 0.10.0 and I'm trying to retrieve the video size but it's returning ZERO for height and width values.
However, I am able to play the video with no problems on a QImage.
QGst::init();
pipeline = QGst::Pipeline::create();
filesrc = QGst::ElementFactory::make("filesrc");
filesrc->setProperty("location", "sample.avi");
pipeline->add(filesrc);
decodebin = QGst::ElementFactory::make("decodebin2").dynamicCast<QGst::Bin>();
pipeline->add(decodebin);
QGlib::connect(decodebin, "pad-added", this, &MyMultimedia::onNewDecodedPad);
QGlib::connect(decodebin, "pad-removed", this, &MyMultimedia::onRemoveDecodedPad);
filesrc->link(decodebin);
// more code ...
The code above shows the begining of the pipeline setup. By connecting my method MyMultimedia::onNewDecodedPad on the signal "pad-added" I have access to the data of the video. At least that's what I think.
void MyMultimedia::onNewDecodedPad(QGst::PadPtr pad)
{
QGst::CapsPtr caps = pad->caps();
QGst::StructurePtr structure = caps->internalStructure(0);
if (structure->name().contains("video/x-raw"))
{
// Trying to print width and height using a couple of different ways,
// but all of them returns 0 for width/height.
qDebug() << "#1 Size: " << structure->value("width").get<int>() << "x" << structure->value("height").get<int>();
qDebug() << "#2 Size: " << structure->value("width").toInt() << "x" << structure->value("height").toInt();
qDebug() << "#3 Size: " << structure.data()->value("width").get<int>() << "x" << structure.data()->value("height").get<int>();
// numberOfFields also returns 0, which is very wierd.
qDebug() << "numberOfFields:" << structure->numberOfFields();
}
// some other code
}
I wonder what I might be doing wrong. Any tips? I was unable to find a relevant example on the web using this API.
Solved it. At onNewDecodedPad() you still don't have access to information about the video frames.
The class MyMultimedia inherits from QGst::Utils::ApplicationSink, so I had to implement a method named QGst::FlowReturn MyMultimedia::newBuffer() that is called by QtGstreamer whenever a new frame is ready.
In other words, use this method to copy the frame of the video to a QImage. What I didn't know is that pullBuffer() returns a QGst::BufferPtr, which has a QGst::CapsPtr. It's an internal structure from this var that holds the information I was looking for:
QGst::FlowReturn MyMultimedia::newBuffer()
{
QGst::BufferPtr buf_ptr = pullBuffer();
QGst::CapsPtr caps_ptr = buf_ptr->caps();
QGst::StructurePtr struct_ptr = caps_ptr->internalStructure(0);
qDebug() << struct_ptr->value("width").get<int>() <<
"x" <<
struct_ptr->value("height").get<int>();
// ...
}