Uninitialized Local Variable in Switch Statement - Win32 API - c++

Alright here is my code I will just provide one function sense the rest of it would not be any helpful. I have been searching for the problem and can not seem to figure it out.
Error: uninitialized local variable 'hTextBox' used Win32Project2
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
HDC hdc;
RECT rect;
PAINTSTRUCT ps;
HWND hTextBox;
switch (message)
{
case WM_CREATE:
hTextBox = CreateWindow(L"edit", L"", WS_CHILD|WS_VISIBLE|WS_BORDER, 5, 5, 200, 25, hwnd, NULL, NULL, NULL);
CreateWindow(L"button", L"Click me!", WS_CHILD | WS_VISIBLE, 20, 40, 75, 25, hwnd, (HMENU)1, NULL, NULL);
break;
case WM_COMMAND:
switch (LOWORD(wparam))
{
case 1:
int returnedCharacters = 0;
returnedCharacters = GetWindowText(hTextBox, &szTextSaved[0], 20);
break;
}
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, L"This is a text message!", -1, &rect, DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}

It is not static, so it won't remember what happened in WM_CREATE

Related

Not receiving pointer after calling GetWindowLongPtr with GWLP_USERDATA

I have a Window procedure which I have defined in a class and I need to be able to access the class' members using the this pointer.
The Window procedure:
static LRESULT CALLBACK TextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
MyCustomClass* self =
reinterpret_cast<MyCustomClass*>(
GetWindowLongPtr(hWnd, GWLP_USERDATA) // Not recieving the pointer!
);
switch(message) {
case WM_DESTROY: {
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)self->origWndProc); // I am subclassing btw.
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
FillRect(hdc, &ps.rcPaint, hBrush);
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, L"OK", -1, &ps.rcPaint, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
SetBkMode(hdc, OPAQUE);
EndPaint(hWnd, &ps);
DeleteObject(hBrush);
break;
}
case WM_LBUTTONDOWN: {
printf("%d", self->x); // Crashes the program
break;
}
}
return CallWindowProc(self->origWndProc, hWnd, message, wParam, lParam); // Subclassing!
}
Now after creating the window (a text control in my case) I am immediately setting the pointer to the class using SetWindowLongPtr, like this:
// Variable in the class that holds the `HWND` data to the text control.
this->textControl = CreateWindow(
L"STATIC",
L"Hello World!",
WS_CHILD | WS_VISIBLE | SS_NOTIFY,
this->x, this->y, this->width, this->height, // Position and size, members defined in the class
this->parentWindow, // Parent window.
0,
NULL,
NULL
);
SetWindowLongPtr(this->textControl, GWLP_USERDATA, (LONG_PTR)this); // Setting the pointer
this->origWndProc = (WNDPROC)SetWindowLongPtr(this->textControl, GWLP_WNDPROC, (LONG_PTR)this->TextWndProc); // Setting the window procedure for "Subclassing"!
But the problem is I am not receiving the this pointer when I am calling GetWindowLongPtr as seen in the Window procedure.
Am I calling it wrong? I don't know what is wrong.
Any help would be greatly appreciated! Thank you in advance!

How to make WM_PAINT run from outside of wndproc

I apologize if this is a dumb question, im just starting to learn winapi. here is the code in concern:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WCHAR greeting[] = _T("line1");
WCHAR greeting1[] = _T("another line");
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
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_PAINT:
{
repaint = false;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
switch (pageID) {
case 1: {//display first string
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
break;
}
case 2: {//display the other string
TextOut(hdc, 5, 100, greeting1, _tcslen(greeting1));
break;
}
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
/*****************************************************************************/
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
pageID = 1;
repaint = true;
}
if (LOWORD(wParam) == IDC_BUTTON1) {
pageID = 2;
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
I apologize for the seemingly random variables that don't do anything, I was just trying to make this work any way possible, but no dice.
What I am trying to do, is to have one of the textouts run after a button is pressed in a dialog box. Unfortunately, the text isn't displayed until wndproc runs next time. UpdateWindow is useless, because I need to pass hWnd to it, but I can't do that when Im not in wndproc. Need a quick tip on how this should be done. Im sure everyone does it every day, just not obvious for me... Thanks!
Basically use InvalidateRect, but this comment
UpdateWindow is useless, because I need to pass hWnd to it, but I
can't do that when Im not in wndproc.
exhibits kind of a fundamental misunderstanding of how Win32 programming works. You always need a window handle to a window you are working with. You get window handles when you create windows; you need to store those somewhere.
Anyway below is a minimal version of using buttons on one window to drive repainting of another window.
#include <windows.h>
HINSTANCE g_hInstance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SomeOtherWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
const int kBtn1ID = 101;
const int kBtn2ID = 102;
int pageID = 1;
HWND g_other_hwnd = NULL;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"foobar";
if (!RegisterClass(&wc))
return 1;
wc.lpszClassName = L"some_other_window";
wc.lpfnWndProc = SomeOtherWndProc;
if (!RegisterClass(&wc))
return 1;
g_hInstance = hInstance;
if (!CreateWindow(L"foobar",
L"foobar",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL))
return 2;
if (!(g_other_hwnd = CreateWindow(L"some_other_window",
L"quux",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL)))
return 2;
while (GetMessage(&msg, NULL, 0, 0) > 0)
DispatchMessage(&msg);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
CreateWindow(L"button", L"some button", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 10, 10, 150, 35, hWnd, (HMENU)kBtn1ID, g_hInstance, 0);
CreateWindow(L"button", L"some other button", BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 10, 55, 150, 35, hWnd, (HMENU)kBtn2ID, g_hInstance, 0);
break;
case WM_COMMAND: {
int btn_id = LOWORD(wParam);
switch (btn_id) {
case kBtn1ID:
pageID = 1;
InvalidateRect(g_other_hwnd, NULL, TRUE);
break;
case kBtn2ID:
pageID = 2;
InvalidateRect(g_other_hwnd, NULL, TRUE);
break;
}
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK SomeOtherWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
static auto greeting = L"hello there.";
static auto greeting1 = L"goodbye.";
switch (pageID) {
case 1: {//display first string
TextOut(hdc, 5, 5, greeting, lstrlenW(greeting));
break;
}
case 2: {//display the other string
TextOut(hdc, 5, 100, greeting1, lstrlenW(greeting1));
break;
}
}
EndPaint(hWnd, &ps);
}
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

GetWindowtext returning nothing

I'm trying to learn how to make a GUI for a C++ using visual studio. I’ trying to create a button that when you push it a textbox with the content of a edit window appear, but the GetWindowText function is Returning a blank string when I run my program. I have tried to adjust the size of the buffer to see if that is the problem, but I haven’t been able to solve it that way. I have tried using number instead of the GetWindowTextLength() funktion, but I could not get it to work that way.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{` HMENU hMenubar = CreateMenu();
HMENU hFile = CreateMenu();
HMENU hOptions = CreateMenu();
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hFile, L"File");
AppendMenu(hMenubar, MF_POPUP, NULL, L"Edit");
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hOptions, L"Options");
AppendMenu(hFile, MF_STRING, NULL, L"Exit");
AppendMenu(hOptions, MF_STRING, NULL, L"option 1");
AppendMenu(hOptions, MF_STRING, NULL, L"option 2");
SetMenu(hWnd, hMenubar);
CreateWindow(TEXT("button"), TEXT("Hello"),
WS_VISIBLE | WS_CHILD,
10, 10, 80, 25,
hWnd, (HMENU) ID_BUTTON1, NULL, NULL);
static HWND hWndTextbox = CreateWindow(TEXT("edit"), TEXT("sim"),
WS_VISIBLE | WS_CHILD|WS_BORDER | ES_AUTOHSCROLL,
90, 120, 300, 20,
hWnd, (HMENU) ID_TEXT3, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("shiny"),
WS_VISIBLE | WS_CHILD,
50, 50, 80, 50,
hWnd, (HMENU) ID_BUTTON2, NULL, NULL);
}
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_BUTTON1) {
MessageBox(hWnd, TEXT("Button has been clicked"), TEXT("title for popup"), MB_ICONINFORMATION);
}
if (LOWORD(wParam) == ID_BUTTON2) {
// create some default vars
// Allocate buffer including terminating null
int length = GetWindowTextLength(hWndTextbox) + 1;
std::wstring uinput(GetWindowTextLength(hWndTextbox) + 1, 0);
// Address of first character is used to obtain pointer to non-const data
// (as opposed to wstring::c_str()).
int size = GetWindowText(hWndTextbox, &uinput[0], length+1);
// Resize buffer to the actual text length
uinput.resize(size);
// MessageBox only needs pointer to const string, so we can use wstring::c_str() here.
MessageBox(hWnd, uinput.c_str(), TEXT("Message box"), MB_OK);
}
break;
int wmId = LOWORD(wParam);
// Parse the menu selections:
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_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}`
the rest of the code was auto generated by visual studio so I have only included the part where I made changes

get scrollbar id on windows procedure

Here is how I create my scrollbar:
CreateWindowEx(NULL, L"SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE | scrollPos, x, y, width, height, parent, (HMENU)155, GetModuleHandle(NULL), NULL);
How could I restore my id (155) to know which control I will operate?
Here is how I tried:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
int id;
SCROLLBARINFO si;
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (message)
{
case WM_USER:
break;
case WM_USER + 1:
break;
case CONNECT_TO_SERVER:
break;
case WM_VSCROLL:
id = GetDlgCtrlID(hWnd);
//id isn't my 155 id, it is some kind of random number
//wmId isn't my 155 id
break;
case WM_COMMAND:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I need to regain this id to choose which one of my controls should react inside my own grid.
id = GetDlgCtrlID(hWnd);
That's not correct, hWnd is the handle to your main window, not the scrollbar control. Also beware that WM_VSCROLL can be sent both by your main window and the scrollbar. The lParam argument tells you where it came from. Fix:
case WM_VSCROLL:
if (lParam != 0) {
int id = GetDlgCtrlID((HWND)lParam);
// etc..
}
break;

Win32 - cannot trigger WM_PAINT message with RedrawWindow()

I am trying to trigger a WM_PAINT message form WM_TIMER; the timer works, but RedrawWindow() function does not seem to do anything. What am I doing wrong?
Here is my Callback function:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
PAINTSTRUCT Ps;
COLORREF clrBlue = RGB(25, 55, 200);
RECT Recto = { 20, 28, 188, 128 };
COLORREF clrAqua = RGB(128, 255, 255);
COLORREF clrRed = RGB(255, 25, 5);
static bool x = true;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
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:
//InvalidateRect(hWnd ,NULL , FALSE);
//RedrawWindow(hWnd , NULL , NULL , RDW_INVALIDATE);
RedrawWindow(hWnd,NULL,NULL,RDW_INTERNALPAINT);
break;
case WM_PAINT:
if(x)
{
hdc = BeginPaint(hWnd, &ps);
SetTextColor(hdc, clrRed);
TextOut(hdc, 50, 42, L"Some text", 13);
EndPaint(hWnd, &ps);
toggle(x);
}
else
{
hdc = BeginPaint(hWnd, &ps);
SetTextColor(hdc, clrRed);
TextOut(hdc, 50, 42, L"Another text", 13);
EndPaint(hWnd, &ps);
toggle(x);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
As x is defined as a local variable in your function, it always gets the value true when the function is called. That is, the code in WM_PAINT never gets to the else branch of the if.
Try, for example, changing the definition of x to static bool x = true; to get the toggling work.
Additionally, you need to invalidate the window's contents to get it redrawn:
RedrawWindow(hWnd,NULL,NULL,RDW_INVALIDATE | RDW_INTERNALPAINT);