C++ Win32: HDC's and debugging - c++

I'm writing code for what should be a tetris game. It's early on, and right now it only displays a single piece (the piece that would be "falling" at that point), which is all it should do. The up arrow allows you to cycle forward (specifically only) through a randomly generated sequence of pieces (using the "bag" method). And, using the left and right arrows, you can rotate the pieces. Anyways, it's coded on a win32 platform, and I've found that after a certain number of frames (running WM_PAINT) the main HDC turns null and everything stops. It takes roughly twice as many frames of holding down the right or left arrow keys to achieve this as it does to hold down the up arrow key. Something odd is that after about 1000 frames the area of the console that I'm actively painting over (a 600x600 px frame) will go black (the hdc has not been nullified yet), and it's only when the up arrow is pressed that the hdc is nullified. What I suspect to be the problem is that the methods called when the up arrow key is pressed pass the hdc as a parameter to the in-class methods (tell me if this is poor practice or there's something I should be doing instead). I think the hdc might be corrupting or something (honestly I have no idea). The left and right arrow keys don't directly call methods with HDC's as a parameter. Because of case labels and how the win32 template is designed, I have to store an HDC who's scope falls out of any case-label, so that I can access the window's handle outside of the paint case (I feel like this is poor practice, but I'd like to understand why before I go out of my way to find a new way). I'll post the code, the stored HDC is called mainHDC, and it's defined just before the main case statement. To clue you in, I'll give an overview of the code structure:
The main .cpp file, which contains the basic win32 program, calls the Tetris class constructor in WM_PAINT and stores it universally like the mainHDC is and, when prompted, the "next" method (which brings the next piece), the "turnPiece" method (which rotates the piece clockwise or counter-clockwise based on the paramter), and the "paint" method which updates the screen, repainting the current piece. In the tetris class (which is in it's own header file), there is a sub-class called "pieces" which contain information about its objects, that are defined by another level of sub-classes named with a single character depicted by the pieces shape. The shape, color, and size of the pieces are stored in a 2d array of pointers (using COLORREF). "Pieces" contains its own "DrawObject" method which draws the object that calls it (which like all of the drawing/painting methods have an HDC as an argument). There's also a method that rotates the shape called "turnTet" (the "turnPiece" method relays the call from the main .cpp file to "pieces"). The only other applicable methods are those found in the "tetris" class which are "paint" and "next" (they ultimately paint the object). The WM_KEY cases, excluding the VK_UP case, don't use the saved hdc but rather use InvalidateRect().
Here's the applicable part of the .cpp file
int tempt = 2;
int tempvar = 0;
tetris *mainOBJ;
HDC mainHDC;
HDC testHDC;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
mainOBJ->turnPiece(false);
InvalidateRect(hWnd, 0, FALSE);
break;
case VK_RIGHT:
mainOBJ->turnPiece(true);
InvalidateRect(hWnd, 0, FALSE);
break;
case VK_UP:
mainOBJ->next(mainHDC);
InvalidateRect(hWnd, 0, FALSE);
break;
}
break;
case WM_COMMAND:
//Non-applicable & has not been changed
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
mainHDC = hdc;
HPEN oldP;
HPEN newP;
COLORREF qLC;
qLC = RGB(0, 0, 0);
newP = CreatePen(PS_SOLID, 1, qLC);
oldP = (HPEN) SelectObject(hdc, newP);
tempt++;
//USED FOR COUNTING FRAMES WITH DEBUGGER
if (tempt % 1 == 0) {
if (tempvar == 0) {
//CONSTRUCTOR CALL
mainOBJ = new tetris(hdc);
tempvar++;
}
//PAINT METHOD CALL
mainOBJ->paint(hdc);
}
if (hdc == NULL) {
int x = 3;
int y = x + 3; //SET DEBUG_BREAK POINT HERE
}
testHDC = hdc;
SelectObject(hdc, oldP);
DeleteObject(newP);
EndPaint(hWnd, &ps);
}
break;
}
}
The header file, which contains the Tetris and piece classes
class tetris {
public:
class pieces {
private:
COLORREF **test;
int size;
public:
//Abbreviated for space
class O {};
class I {};
class S {};
class Z {};
class T {};
class L {};
class J {};
void setSize(int a) {
//Initializing the piece-array
test = new COLORREF*[a];
size = a;
int i = 0;
while (i < a) {
test[i] = new COLORREF[a];
i++;
}
}
void setShape(COLORREF **shape) {
test = shape;
}
void setColor(HDC hdc, COLORREF rgb) {
HPEN Penn = CreatePen(PS_SOLID, 1, rgb);
HPEN Peno = (HPEN)SelectObject(hdc, Penn);
}
static pieces getObject(char type) {
pieces Gen;
switch (type) {
case 'O':
{
//Identical (almost) to the other cases
O pcs = O();
Gen = *pcs.getObject();
return Gen;
}
break;
case 'I':
case 'S':
case 'Z':
case 'T':
case 'L':
case 'J':
return pieces();
}
void turnTet(bool clockwise) {
int i = 0;
int s;
COLORREF **shape;
int ter = size - 1;
shape = new COLORREF*[2];
while (i < size) {
shape[i] = new COLORREF[2];
s = 0;
while (s < size) {
shape[i][s] = def;
s++;
}
i++;
}
i = 0;
while (i < size) {
s = 0;
while (s < size) {
if (clockwise) {
shape[s][ter - i] = test[i][s];
}
else {
shape[ter - s][i] = test[i][s];
}
s++;
}
i++;
}
test = shape;
}
void drawObject(HDC hWnd) {
int i = 0;
int s;
while (i < size) {
s = 0;
while (s < size) {
setColor(hWnd, test[i][s]);
int scaleOfBox = 90;
DrawBox((s + 1) * scaleOfBox, (i + 1) * scaleOfBox, scaleOfBox - 1, scaleOfBox - 1, hWnd);
s++;
}
i++;
}
}
void DrawBox(int x, int y, int w, int h, HDC hdc) {
if (h < 0) {
h *= -1;
}
if (w < 0) {
w *= -1;
}
int i = 0;
while (i < h) {
MoveToEx(hdc, x, y + i, NULL);
LineTo(hdc, x + w, y + i);
i++;
}
}
};
tetris(HDC hdc) {
refresh();
bagp[cur].drawObject(hdc);
}
void next(HDC hdc) {
bagp[cur].DrawBox(0, 0, 600, 600, hdc);
bagp[cur].drawObject(hdc);
cur++;
if (cur > 6) {
refresh();
}
}
void turnPiece(bool clockwise) {
bagp[cur].turnTet(clockwise);
}
void refresh() {
srand(time(NULL));
bag[0] = rand() % 7;
int i = 1;
while (i < 7) {
bool open = false;
cur = i;
while (!open) {
bag[i] = rand() % 7;
int s = 1;
open = true;
while (s <= i) {
if (bag[i] == bag[i - s]) {
open = false;
}
s++;
}
}
i++;
}
cur = 0;
while (cur < 7) {
switch (bag[cur]) {
case 0:
bagp[cur] = pieces::getObject('O');
break;
case 2:
bagp[cur] = pieces::getObject('T');
break;
case 1:
bagp[cur] = pieces::getObject('I');
break;
case 3:
bagp[cur] = pieces::getObject('S');
break;
case 4:
bagp[cur] = pieces::getObject('Z');
break;
case 5:
bagp[cur] = pieces::getObject('L');
break;
case 6:
bagp[cur] = pieces::getObject('J');
break;
}
cur++;
}
cur = 0;
}
void paint(HDC hdc) {
COLORREF temp = def;
bagp[cur].setColor(hdc, temp);
bagp[cur].DrawBox(0, 0, 600, 600, hdc);
bagp[cur].drawObject(hdc);
}
private:
int bag[7];
int cur;
pieces bagp[7];
};
I don't understand why the HDC nullifies like it does. Once again I suspect it's related to how the hdc is passed as a parameter or maybe how I'm saving the hdc. Help...please (and thank you).

Ooh, old school windows programming...
This may not be the entirety of the problem, but in your setColor function you're creating a Pen with CreatePen but never calling DeleteObject on it. This will leak the resource and eventually cause problems when Windows runs out of resource handles for objects.
Also, the Device Context returned by BeginPaint is (generally) only valid until EndPaint is called (unless you specify otherwise in the CreateWindow call, if I remember rightly). This can be another source of handle leakage.
In the Process tab of Task Manager, you can add the "GDI objects" column which will have an increasing number as your program runs if you're leaking handles. I saw this once with something I wrote way back when.

Related

How to make a button that will go to the previous menu in ncurses

I am pretty new to c++ and ncurses, so sorry if my question is weird or obvious.
I managed to make a simple tui program that will do various tasks, my problem is that I have no back functionality or something that would loop the program.
I want to be able to go back to the main menu after accessing one of the submenus and I want to make the program repeat after it's done so I won't have to keep opening it over and over, so do you have any solutions that I can apply?
Thank you in advance
This is my code:
int main(int argc, char ** argv)
{
int i=0;
string input;
initscr();
noecho();
cbreak();
curs_set(0);
int yMax, xMax;
getmaxyx(stdscr, yMax, xMax);
WINDOW * menuwin = newwin (0, xMax, 0, 0);
leaveok(menuwin, true);
refresh();
wrefresh(menuwin);
keypad(menuwin, true);
string choices[4] = {"Youtube","Music","Anime","Games"};
int choice;
int highlight = 0;
int option = 0;
while(1)
{
for (i=0;i < 4; i++)
{
if(i == highlight)
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, choices[i].c_str());
wattroff(menuwin, A_REVERSE);
}
choice = wgetch(menuwin);
switch(choice)
{
case KEY_UP:
highlight--;
if(highlight == -1)
highlight = 3;
break;
case KEY_DOWN:
highlight++;
if(highlight == 4)
highlight = 0;
break;
default:
break;
}
if(choice == 10)
{
break;
}
}
werase(menuwin);
switch(highlight)
{
case 0:
{
menu2();
break;
}
case 1:
{
menu3();
break;
}
case 2:
{
menu4();
break;
}
case 3:
{
menu2();
}
default:
break;
}
endwin();
return 0;
}

Infinite loop makes the program stop working

So I'm creating a program, where 5 rectangles are spawned and they move in different directions like DVD Screensaver.
The problem is when I start moving them in infinite loop the program stops working not allowing any input to be made. If I make the loop not infinite, it will stop working until the loop ends, and after that the program allows you to do something.
I think the problem is in the way I try to move the rectangles, but I'm not sure.
void MovePredator(HDC hdc, PAINTSTRUCT ps,int size, int amount)
{
for (;;)
{
FillRect(hdc, &ps.rcPaint, (HBRUSH)(1));
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
Sleep(10);
}
}
void SpawnPredator(HDC hdc, int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand()%2;
Predator[i].MoveY = rand()%2;
if (Predator[i].MoveX == 0) Predator[i].MoveX = -1;
if (Predator[i].MoveY == 0) Predator[i].MoveY = -1;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
This is how the loop interacts (I deleted cases that it doesn't interact with)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
srand(time(NULL));
// TODO: Добавьте сюда любой код прорисовки, использующий HDC...
SpawnPredator(hdc, 50, 5);
MovePredator(hdc, ps, 50, 5);
EndPaint(hWnd, &ps);
}
}
}
The reason of this application hang is in nature of Windows application event based design.
What is going on at the background, any windows application is not allowed to access any hardware directly unlike operating system which able to run only one program at time like DOS for example. This is needed to share hardware like video card or mouse between multiple programs. Instead of the direct access to hardware, Windows kernel manipulate the hardware itself when running applications sending special request to the kernel (system calls), Win API is actually a set of functions can be used to send such request to the kernel.
When your application creates or draws into a Window, it actually asking operating system kernel to do it. Kernel select when and how to process this operation, and then use video card device driver to draw (over the hardware abstraction layer or special fast APIs like OpenGL or Direct X etc.).
Another thing - how application would know if user do some input using a mouse or keyboard. Windows stores those inputs in the special internal queue of structures - called events, each application thread have such a queue.
Application itself should have a loop which waits for an OS event, and react on them - such loops called run loop and usually looks like following:
MSG messages; // Here messages to the application are saved
// Run the message loop. It will run until GetMessage() returns 0
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
If you are using a library like MFC this loop is provided by the library, however it is still exist.
When you have created a window, you or your library – register a WindowProcedure callback function, this function react on messages run loop send to a window object like WM_PAINT. Such function usually calls to DefWindowProc function when your program don’t needs to handle some specific event.
WM_PAINT occurs when you maximize, minimize, restores or show hide a window, or you can send this message to window yourself using SendMessage function.
If you will do an infinity loop, or block a thread doing the run loop during handling a message – it will freezes run loop, as well as DefWindowProc or another custom messages handling would not be called when they needs to be called, and your application hangs.
Following MSDN article shows how to make an animation you’d like to implement.
DO NOT perform infinite loops inside of a UI message handler. This is the main reason why your app does not work. You are not allowing your app to stay responsive to messages from the OS.
Also, DO NOT perform non-drawing logic inside a paint handler. Updating your predators is not a task that belongs in your WM_PAINT event at all. Use a timer instead, and have it invalidate the window to trigger a repaint whenever a change occurs. Simply paint the existing predators as-is whenever you are asked to paint the window.
Also, your WndProc() is missing a call to DefWindowProc() for all unhandled messages.
Try something more like this:
void MovePredator(int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
}
}
void SpawnPredator(int amount)
{
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand() % 2;
Predator[i].MoveY = rand() % 2;
if (Predator[i].MoveX == 0)
Predator[i].MoveX = -1;
if (Predator[i].MoveY == 0)
Predator[i].MoveY = -1;
}
}
void PaintPredator(HDC hdc, int size, int amount)
{
int Offset = size / 2;
for (int i = 0; i < amount; ++i)
{
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
srand(time(NULL));
SetTimer(hWnd, 1, 10, NULL);
return 0;
case WM_TIMER:
SpawnPredator(5);
MovePredator(50, 5);
InvalidateRect(hWnd, NULL);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(1));
PaintPredator(hdc, 50, 5);
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Thanks to everyone who helped. This is my final setup (I will edit this post if I find a better way to do this)
#define STEP 1
int idtimer = -1;
struct Mob
{
int LocationX = 0;
int LocationY = 0;
int MoveX = 0;
int MoveY = 0;
};
struct Mob Predator[100];
void SpawnPredator(int amount)
{
for (int i = 0; i < amount; ++i)
{
Predator[i].LocationX = rand() % 1300 + 50;
Predator[i].LocationY = rand() % 600 + 50;
Predator[i].MoveX = rand() % 2;
Predator[i].MoveY = rand() % 2;
if (Predator[i].MoveX == 0) Predator[i].MoveX = -STEP;
else Predator[i].MoveX = STEP;
if (Predator[i].MoveY == 0) Predator[i].MoveY = -STEP;
else Predator[i].MoveY = STEP;
}
}
void MovePredator(int size, int amount)
{
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
if (Predator[i].LocationX - Offset <= 0 || Predator[i].LocationX + Offset >= 1420)
{
Predator[i].MoveX *= -1;
}
if (Predator[i].LocationY - Offset <= 0 || Predator[i].LocationY + Offset >= 700)
{
Predator[i].MoveY *= -1;
}
Predator[i].LocationX += Predator[i].MoveX;
Predator[i].LocationY += Predator[i].MoveY;
}
}
void PaintPredator(HDC hdc, int size, int amount)
{
for (int i = 0; i < amount; ++i)
{
int Offset = size / 2;
Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
srand(time(NULL));
switch (message)
{
case WM_CREATE:
{
SpawnPredator(5);
SetTimer(hWnd, idtimer = 1, 10, NULL);
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Разобрать выбор в меню:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_TIMER:
{
MovePredator(50, 5);
InvalidateRect(hWnd, NULL, FALSE);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(4));
PaintPredator(hdc, 50, 5);
//Rectangle(hdc, 0, 10, 20, 30);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}

Visual C++ Debug Assertion Fail

When Ever I compile my program it say "Debug Assertion Failed".
And when I click ignore twice my app shows up.
How can I fix it?
The whole code is below in case you want to test it for your self. The app increases in number as the scroll bar is moved to the right and decreases as the scroll bar is moved to the left. But my main problem is the debug assertion failed. If you can please post the part of the code that has problem and how I can fix it or fix it and post the code. Is there any way to get rid of that run time error with out using a try and catch. I mean to fix that problem please. This is a project and I have only a week and a half to do it. If you can help me with this project your help would be greatly appreciated. I am fairly new to visual c++. Part of the error is:
Program E:\BHCCHardwareStore\Debug\BHCCHardwareStore.exe FIle:f\dd\vctools\vc7libs\ship\atlmfc\src\mfc\appcore.cpp Line: 196. For information on how your program can cause an assertion failure see the Visual C++ documentation on asserts.
(Press Retry to debug the application).
Now when I click ignore it kind of displays the app perfectly fine. And the app seems to work just fine. How can I fix this error This code is not the entire code I am cutting and pasting?
#include "stdafx.h"
#include <strstream>
#include <afxwin.h>
#include <string.h>
const int IDC_SB1 = 100;
const int IDC_CS1 = 101;
const int IDC_CS2 = 102;
const int IDC_BUTTON = 103;
const int MIN_RANGE = 0;
const int MAX_RANGE = 100;
class CApp :public CWinApp
{
public:
virtual BOOL InitInstance();
};
CApp App;
class CSource :public CFrameWnd
{
CScrollBar*sb1;
CStatic* cs1;
CStatic* cs2;
CButton* button;
public:
CSource();
afx_msg void OnHScroll(UINT nSBCode,
UINT nPos, CScrollBar* pSccrollBar);
afx_msg void handleButton();
DECLARE_MESSAGE_MAP();
};
BEGIN_MESSAGE_MAP(CSource, CFrameWnd)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_BUTTON, handleButton)
END_MESSAGE_MAP()
//Window cONSTRUCTOR
CSource::CSource()
{
}
void CSource::OnHScroll(UINT nSBCode,
UINT nPos, CScrollBar* pScrollBar)
{
int pos, dividend = 0, holder = 0, x = 0;
char array[9];
//;
pos = pScrollBar->GetScrollPos();
switch (nSBCode)
{
case SB_LINEUP:
pos -= 1;
break;
case SB_LINEDOWN:
pos += 1;
break;
case SB_PAGEUP:
pos -= 10;
break;
case SB_PAGEDOWN:
pos += 10;
break;
case SB_TOP:
pos = MIN_RANGE;
break;
case SB_BOTTOM:
pos = MAX_RANGE;
break;
case SB_THUMBTRACK:
pos = nPos;
break;
default:
return;
}
if (pos < MIN_RANGE)
pos = MIN_RANGE;
else if (pos > MAX_RANGE)
pos = MAX_RANGE;
sb1->SetScrollPos(pos, TRUE);
//Set the labels to the new values
char s[100];
TCHAR s1[100];
std::ostrstream ostr(s, 100);
ostr << "Decimal Value = " << pos << std::ends;
for (int i = 0; i < 100; i++){
s1[i] = (TCHAR) s[i];
}
SetDlgItemText(IDC_CS1, s1);
ostr.seekp(std::ios::beg);
dividend = pos;
for (int y = 0; y < 9; y++)
array[y] = '0';
int remainder = dividend % 2;
int quotient = dividend / 2;
array[x] = (char)(remainder + 48);
do
{
remainder = quotient % 2;
quotient = quotient / 2;
array[++x] = (char)(remainder + 48);
} while (quotient != 0);
array[8] = '\0';
ostr << "Binary Value = " << _strrev(array) << std::ends;
SetDlgItemText(IDC_CS2, s1);
}
void CSource::handleButton()
{
int result;
result = MessageBox(_T("Are you sure?"), _T("Exiting"),
MB_ICONQUESTION | MB_YESNO);
if (result == IDYES)
{
Beep(1000, 100);
DestroyWindow();
}
else
Beep(200, 100);
}
//Initialize the application and the main window
BOOL CApp::InitInstance()
{
m_pMainWnd = new CSource();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
Your code (in VS2013) produces assertion in MFC code:
BOOL CWnd::ShowWindow(int nCmdShow)
{
ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));
From your call:
m_pMainWnd->ShowWindow(m_nCmdShow);
You must create your window first, before you can show it.

Clearing a field buffer in ncurses

I've built a generic wrapper for the curses form object to use with a large
simulation project that I'm working on.
Basically, I instantiate an generic_form object, add some fields and their
descriptions to it, and then give it focus and get user input with a fill_form() routine.
Because each generic_form object can be used more than once, that is, that fill_form() may be called more than once per instantiation, I need to clear the field buffers at the beginning of the fill_form() routine. Currently, I'm using this at the beginning of the routine:
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
However, it throws a floating point exception at the set_field_buffer line on the second call to the fill_form() routine. Moreover, the set_field_buffer line doesn't seem to actually be doing anything, at least not clearing the buffer, because without calling free_field at the end of the routine, and instead in the object destructor, the fields buffers remain the same on each subsequent call.
Here's the entirety of the (ugly, in-development) fill_form() routine for brevity:
void generic_form::fill_form()
{
//fields.push_back(NULL);
if (fields.size() == 1)
{
fields.push_back(NULL);
form = new_form(static_cast<FIELD**>(fields.data()));
fields.erase((fields.end() - 1));
assert(fields.size() == 1);
}
else
{
form = new_form(static_cast<FIELD**>(fields.data()));
}
WINDOW* form_win = derwin(screen, fields.size() + 1, largest_desc + 6, ypos,
xpos);
set_form_win(form, form_win);
set_form_sub(form, form_win);
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
post_form(form);
for (int x = 0; x < descriptions.size(); x++)
{
mvwprintw(form_win, x, 0, descriptions.at(x).c_str());
}
wmove(form_win, 0, largest_desc + 1);
touchwin(screen);
wrefresh(form_win);
/* Loop through to get user requests */
int ch;
while((ch = getch()) != '\n')//KEY_F(1))
{ switch(ch)
{
case KEY_DOWN:
/* Go to next field */
form_driver(form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
/* Go to previous field */
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
/* If this is a normal character, it gets */
/* Printed */
form_driver(form, ch);
break;
}
}
form_driver(form, REQ_VALIDATION);
for (int x = 0; x < fields.size() && first_run; x++)
{
//store the int_inputs from the forms
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_INTEGER))
{
int_inputs.push_back(std::atoi(field_buffer((fields.at(x)), 0)));
}
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_ALPHA))
{
str_inputs.push_back(field_buffer((fields.at(x)), 0));
}
}
first_run = false;
/* Un post form and free the memory */
unpost_form(form);
free_form(form);
for (int x = 0; x < fields.size(); x++)
{
free_field(fields.at(x));
}
delwin(form_win);
}
Long story short/TLDR:
How to I clear or reset a field buffer in ncurses, without deleting and re-adding it?
You can clean field buffer using form_driver ()
Excerpt man form_driver
REQ_CLR_EOL
Clear to end of line from cursor.
REQ_CLR_EOF
Clear to end of field from cursor.
REQ_CLR_FIELD
Clear the entire field.
To elaborate this a bit more :-), I'm using code similar to following for clearing fields:
#include <stdio.h>
#include <stdlib.h>
#include <form.h>
enum f_name_l
{
f_name, f_surname, f_last
};
int main (void)
{
int ch = 0, i = 0;
FIELD *field[3], *save_field;
FORM *my_form;
initscr ();
start_color ();
noecho ();
raw ();
keypad (stdscr, TRUE);
refresh ();
field[f_name] = new_field (1, 10, 0, 25, 0, 0);
field[f_surname] = new_field (1, 10, 2, 25, 0, 0);
field[f_last] = NULL;
set_field_back (field[f_name], A_UNDERLINE);
set_field_back (field[f_surname], A_UNDERLINE);
my_form = new_form (field);
post_form (my_form);
// Form labels
mvprintw (0, 1, "Name: ");
mvprintw (2, 1, "Surname: ");
mvprintw (4, 1, "F5 to clear active field. F6 to clear form.");
pos_form_cursor (my_form);
refresh ();
// ^q to exit
while ((ch = getch ()) != 17)
{
switch (ch)
{
case KEY_UP:
form_driver (my_form, REQ_PREV_FIELD);
break;
case KEY_DOWN:
form_driver (my_form, REQ_NEXT_FIELD);
break;
case KEY_F(5):
form_driver (my_form, REQ_CLR_FIELD);
break;
case KEY_F(6):
save_field = current_field (my_form);
for (i = 0; i < f_last; i++)
{
set_current_field (my_form, field[i]);
form_driver (my_form, REQ_CLR_FIELD);
}
set_current_field (my_form, save_field);
break;
default:
form_driver (my_form, ch);
break;
}
form_driver (my_form, REQ_VALIDATION);
}
endwin ();
return EXIT_SUCCESS;
}
But seeing post from Thomas Dickey I start to feel like my life is a lie :-).

C4533 warning: why does goto skip variable initialization?

I'm getting:
warning C4533: initialization of 'b' is skipped by goto FreeDC.
But if the code gets to the label FreeDC in WM_CREATE, 'b' is not initialized. How its initialization could be skiped, if it is not initialized in that situation. I just don't understand the warning.
#include <windows.h>
class A
{
int i;
public:
A() {};
A(int i) : i(i) {}
};
LRESULT CALLBACK WndProc(HWND, UINT, UINT, LONG);
HINSTANCE ghInstance;
/************************************************************************************************************************
WinMain(hInstance, hPrevInstance, pszCmdLine, nCmdShow)
************************************************************************************************************************/
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
ghInstance = hInstance;
WNDCLASSEX wndclassx;
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = CS_HREDRAW | CS_VREDRAW;
wndclassx.lpfnWndProc = WndProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = NULL;
wndclassx.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclassx.lpszMenuName = NULL;
wndclassx.lpszClassName = L"WndProc";
wndclassx.hIconSm = NULL;
if( !RegisterClassEx(&wndclassx) ) return 0;
HWND hWnd = CreateWindow(L"WndProc", L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
UpdateWindow(hWnd);
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Retorna msg.wParam
return (int)msg.wParam;
}
/************************************************************************************************************************
WndProc(hwnd, message, wParam, lParam)
************************************************************************************************************************/
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
static A a;
static int i;
switch ( message )
{
case WM_CREATE:
{
HDC hDC;
if( !(hDC = GetDC(hwnd)) ) return -1;
int iLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = -MulDiv(11, iLogPixelsY, 72);
wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Cambria Math");
HFONT hFont;
if( !(hFont = CreateFontIndirect(&lf)) ) goto FreeDC;
hFont = (HFONT)SelectObject(hDC, hFont);
int j = 5;
i = j;
A b(2);
a = b;
return 0;
FreeDC: ReleaseDC(hwnd, hDC);
return -1;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
b's constructor won't called if you use goto, and yet it's still in scope. This is technically an error, although some compilers only give off a warning.
Here's an example:
int main() {
goto foo;
int bar = 5;
foo:
++bar; // doesn't work if goto is used - bar isn't initialized
}
It may seem like you are not using b, but its destructor is still being called:
int main() {
goto foo;
A b;
foo:
b.~A(); // compiler silently adds destructor and other cleanup here
// won't work if goto is used - b isn't initialized
}
You could avoid the problem by introducing a suitable local scope that gets skipped by the goto:
HFONT hFont;
if( !(hFont = CreateFontIndirect(&lf)) )
{
goto FreeDC;
}
hFont = (HFONT)SelectObject(hDC, hFont);
{ // new scope; skipped entirely by goto
int j = 5;
i = j;
A b;
a = b(2);
}
return 0;
FreeDC:
ReleaseDC(hwnd, hDC);
return -1;
If you think about C++ and scopes and automatic object lifetimes really carefully, you'll come to conclude that goto really wreaks havoc with the entire programming model. That's why there are many (often quietly implied) conditions on where you can go-to and wher not. Generally, jumping into the middle of a scope is problematic if the scope contains new automatic variables. We avoid this by introducing a new, local scope that the goto jump skips entirely.
I honestly don't know, but why are you using a goto when an if statement will suffice?
if( (hFont = CreateFontIndirect(&lf)) ) {
hFont = (HFONT)SelectObject(hDC, hFont);
int j = 5;
i = j;
A b;
a = b(2);
return 0;
}
else {
FreeDC: ReleaseDC(hwnd, hDC);
return -1;
}
// break; here is unnecessary.
Consider a smaller, trivial test case:
struct Object {
Object(int i) : i(i) { }
int i;
};
int main() {
Object a(5);
goto Label;
Object b(6);
Label:
cout << a.i << " " << b.i << endl;
}
At that last line, a.i is obviously 5. But what is the value of b.i? When that object was created, it was supposed to be initialized to 6, but you explicitly told the program to skip that line. It could be anything.
Now, lets pretend Object is a more useful type:
struct Object {
Object(int i) : p(new int(i)) { }
~Object() { delete p; }
//insert copy/move constructors/assignment here
int* p;
};
int main() {
Object a(5);
goto Label;
Object b(6);
Label:
cout << *a.p << endl;
}
Now, you never actually use b.p, so it looks like the fact that you skipped the initialization is no big deal. a.p was properly initialized, so this will output 5, no problem. But then you return from main, and destructors start being called... including b.~Object(), which calls delete p;. But b.p was never initialized, so who knows what that line will do?
In these cases, I believe the code is actually ill-formed, and the compiler is required to reject it. It appears that instead of outright rejecting it, the compiler is chosing to warn you about the possible issues, so that you can decide for yourself if there is a concern.
You must not skip an object's initialization with either goto or switch [*](that holds for user-defined types as well as primitive types like ints). In your case, you are not using the object whose initialization you've skipped, so the best solution would be to make this clear to the compiler by limiting the scope of b.
if( !(hFont = CreateFontIndirect(&lf)) ) goto FreeDC;
hFont = (HFONT)SelectObject(hDC, hFont);
int j = 5;
i = j;
{
A b;
a = b(2);
return 0;
}
FreeDC: ReleaseDC(hwnd, hDC);
[*] so these would be illegal:
switch(x) {
case 1:
int y=1;
case 2:
// y not initialized if x==2
and
if (x) goto l;
int y=1;
l: // y not initialized if x!=0
This particularly matters if y is a reference, a constant or a user-defined object with nontrivial constructor.
The standard says it in 6.7/3:
It is possible to transfer into a block, but not in a way that
bypasses declarations with initialization. A program that jumps
from a point where a local variable with automatic storage duration is
not in scope to a point where it is in scope is ill-formed unless the
variable has POD type (3.9) and is declared without an initializer
(8.5).