Window redraw breaks after a few seconds - c++

I have a main HWND with several child HWNDs. When I start the code the windows all draw properly and show up as they should, I can even move the main window around which essentially invokes InvalidateRect() calls which call a redraw of the main and child windows. However, after about two seconds, all of this functionality stops and upon moving the window the main window draw ends up drawing all of the child windows at the size of the main window. Note that this problem occurs with any redrawing of the main window. This is quite strange, and I am inclined to think that the problem lies with my HWND setup and not the OpenGL integration as both my GL child window and the other HWND child windows are subject to the issue.
Here is my main window creation:
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(7, 7, 8));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
//MessageBox(NULL, _T("This message box is completely unnecessary and is designed to annoy you."), _T("Annoyance"), NULL);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
HWND hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1600, 900, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindowEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Here is the main window procedure:
LRESULT CALLBACK WndProc(_In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam) {
//a = std::make_tuple<float, float, float>(1.0f, 0.0f, 0.0f);
PAINTSTRUCT ps;
HDC hdc = GetDC(hWnd);
TCHAR greeting[] = _T("Data Grapher for Paper");
RECT rcClient;
WNDCLASSEXW wcex1;
wcex1.cbSize = sizeof(WNDCLASSEX);
wcex1.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex1.lpfnWndProc = (WNDPROC)GLProc;
wcex1.cbClsExtra = 0;
wcex1.cbWndExtra = 0;
wcex1.hInstance = glInstance;
wcex1.hIcon = LoadIcon(wcex1.hInstance, IDI_APPLICATION);
wcex1.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex1.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
wcex1.lpszMenuName = nullptr;
wcex1.lpszClassName = _T("GLClass");
wcex1.hIconSm = LoadIcon(wcex1.hInstance, IDI_APPLICATION);
RegisterClassExW(&wcex1);
WNDCLASSEXW dataViewClass;
dataViewClass.cbSize = sizeof(WNDCLASSEX);
dataViewClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dataViewClass.lpfnWndProc = (WNDPROC)DataProc;
dataViewClass.cbClsExtra = 0;
dataViewClass.cbWndExtra = 0;
dataViewClass.hInstance = hInst;
dataViewClass.hIcon = LoadIcon(dataViewClass.hInstance, IDI_APPLICATION);
dataViewClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
dataViewClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
dataViewClass.lpszMenuName = nullptr;
dataViewClass.lpszClassName = _T("DataClass");
dataViewClass.hIconSm = LoadIcon(dataViewClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&dataViewClass);
WNDCLASSEXW dataTextClass;
dataTextClass.cbSize = sizeof(WNDCLASSEX);
dataTextClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
dataTextClass.lpfnWndProc = (WNDPROC)dataTextProc;
dataTextClass.cbClsExtra = 0;
dataTextClass.cbWndExtra = 0;
dataTextClass.hInstance = hInst;
dataTextClass.hIcon = LoadIcon(dataTextClass.hInstance, IDI_APPLICATION);
dataTextClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
dataTextClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
dataTextClass.lpszMenuName = nullptr;
dataTextClass.lpszClassName = _T("dataTextClass");
dataTextClass.hIconSm = LoadIcon(dataTextClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&dataTextClass);
WNDCLASSEXW quitButtonClass;
quitButtonClass.cbSize = sizeof(WNDCLASSEX);
quitButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
quitButtonClass.lpfnWndProc = (WNDPROC)quitButtonProc;
quitButtonClass.cbClsExtra = 0;
quitButtonClass.cbWndExtra = 0;
quitButtonClass.hInstance = hInst;
quitButtonClass.hIcon = LoadIcon(quitButtonClass.hInstance, IDI_APPLICATION);
quitButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
quitButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
quitButtonClass.lpszMenuName = nullptr;
quitButtonClass.lpszClassName = _T("quitButtonClass");
quitButtonClass.hIconSm = LoadIcon(quitButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&quitButtonClass);
WNDCLASSEXW saveImageButtonClass;
saveImageButtonClass.cbSize = sizeof(WNDCLASSEX);
saveImageButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
saveImageButtonClass.lpfnWndProc = (WNDPROC)saveImageButtonProc;
saveImageButtonClass.cbClsExtra = 0;
saveImageButtonClass.cbWndExtra = 0;
saveImageButtonClass.hInstance = hInst;
saveImageButtonClass.hIcon = LoadIcon(saveImageButtonClass.hInstance, IDI_APPLICATION);
saveImageButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
saveImageButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
saveImageButtonClass.lpszMenuName = nullptr;
saveImageButtonClass.lpszClassName = _T("saveImageButtonClass");
saveImageButtonClass.hIconSm = LoadIcon(saveImageButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&saveImageButtonClass);
WNDCLASSEXW switchModeButtonClass;
switchModeButtonClass.cbSize = sizeof(WNDCLASSEX);
switchModeButtonClass.style = BS_OWNERDRAW;//CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
switchModeButtonClass.lpfnWndProc = (WNDPROC)switchModeButtonProc;
switchModeButtonClass.cbClsExtra = 0;
switchModeButtonClass.cbWndExtra = 0;
switchModeButtonClass.hInstance = hInst;
switchModeButtonClass.hIcon = LoadIcon(switchModeButtonClass.hInstance, IDI_APPLICATION);
switchModeButtonClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
switchModeButtonClass.hbrBackground = CreateSolidBrush(RGB(27, 27, 28));
switchModeButtonClass.lpszMenuName = nullptr;
switchModeButtonClass.lpszClassName = _T("switchModeButtonClass");
switchModeButtonClass.hIconSm = LoadIcon(switchModeButtonClass.hInstance, IDI_APPLICATION);
RegisterClassExW(&switchModeButtonClass);
switch (message)
{
case WM_PAINT:
/*
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, Windows desktop!"
// in the top left corner.
//doGL(hdc);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
ReleaseDC(hWnd, hdc);
*/
break;
case WM_CREATE:
{
InitCommonControls();
CreateWindowEx(WS_EX_APPWINDOW, _T("quitButtonClass"), _T("Quit"), WS_CHILD, 20, 50, 100, 25, hWnd, (HMENU)1, hInst, NULL);
CreateWindowEx(WS_EX_APPWINDOW, _T("saveImageButtonClass"), _T("Save Image"), WS_CHILD, 140, 50, 80, 25, hWnd, (HMENU)2, hInst, NULL);
CreateWindowEx(WS_EX_APPWINDOW, _T("switchModeButtonClass"), _T("Toggle Clock"), WS_CHILD, 20, 90, 100, 25, hWnd, (HMENU)3, hInst, NULL);
w = CreateWindowEx(WS_EX_APPWINDOW, _T("GLClass"), _T("GL"), WS_CHILD, 0, 0, 160, 90, hWnd, (HMENU)4, hInst, NULL);
HDC dc = GetDC(w);
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
//glfwInit();
int argc = 1;
char* argv[1] = { (char*)"Something" };
glutInit(&argc, argv);
glewInit();
initializeText();
imageSaveQueued = false;
graphScale = .8f;
HWND da = CreateWindowEx(WS_EX_APPWINDOW, _T("DataClass"), _T("Data"), WS_CHILD, 0, 0, 160, 90, hWnd, (HMENU)5, hInst, NULL);
//makes it so the data field accepts files
DragAcceptFiles(da, TRUE);
//set the data mode to by bz graph by default
mode = 1;
//dataList = CreateWindow(WC_LISTVIEW, TEXT("Load Data"), WS_CHILD | LVS_REPORT | LVS_EDITLABELS, 300, 700, 500, 100, hWnd, (HMENU)6, hInst, NULL);
//dataText = CreateWindowEx(WS_EX_APPWINDOW, _T("dataTextClass"), _T("dataText"), WS_CHILD, 200, 200, 200, 200, hWnd, (HMENU)7, hInst, NULL);
//createListColumn(dataList, 1, L"Year", 0);
//createListItem(dataList, _T("Thing"), 0);
//SendMessage(dataList, LB_ADDSTRING, NULL, (LPARAM)"words");
//CreateWindow(TEXT("button"), TEXT("Save Graph"), WS_VISIBLE | WS_CHILD, 140, 90, 100, 25, hWnd, (HMENU)7, NULL, NULL);
//trackA = CreateWindowEx(0, TRACKBAR_CLASS, _T("Start"), WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE, 900, 700, 200, 30, hWnd, (HMENU)8, hInst, NULL);
//trackB = CreateWindowEx(0, TRACKBAR_CLASS, _T("End"), WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE, 900, 730, 200, 30, hWnd, (HMENU)8, hInst, NULL);
//SendMessage(trackA, TBM_SETRANGE,
//(WPARAM)TRUE, // redraw flag
//(LPARAM)MAKELONG(0, 100));
GetClientRect(hWnd, &rcClient);
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&rcClient);
break;
}
case WM_COMMAND:
{
/*
if (LOWORD(wParam) == 2) {
PostQuitMessage(0);
}
*/
if (LOWORD(wParam) == 7) {
smoothLine = !smoothLine;
InvalidateRect(w, NULL, TRUE);
}
break;
}
case WM_DESTROY:
FreeLibrary(comctllib);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
I'm reluctant to paste more code here in the initial question as there is quite a lot more code, but if there is something more needed (including screenshots) I am happy to add it.

Related

Release version not working. Visual Studio C++

I have been programming a Window Application, for Windows, and in Debug mode everything works but when I want switch to release mode the Window that opens in Debug does not open. If I try it without Visual Studio a Task is visible in Task manager but no window.
To be honest right now I can't understand anything I have in this code, I understood it 3 months ago but due to circumstances I have not worked with this in the last months and this is my first window application and my first application I release.
The following code should be everything that handles the creation of the Window.
This program creates a simple user interface (WinAPI) for entering the desired button cycles.
The entered button cycles are then sent to the button test device via a bound TCP / IP client.
As soon as the push button test device is finished with the switching cycles, it transmits the incorrect switching and the task switching to the TCP / IP client.
As soon as the data has been received by the TCP / IP client, it is written to a .csv file by a CSV writer.
*/
#include <Windows.h>
#include <cassert>
#include <wingdi.h>
#include "TCP-IP-Client.h"
HWND hWndEdit;
wchar_t buffer[1024];
LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_COMMAND:
if (LOWORD(wParam) == 10) {
GetWindowText(hWndEdit, buffer, 1024);
int Input[1] = { _wtoi(buffer) };
switch (TcpIpClient(Input)) {
case 10:
MessageBox(hWnd, L"Can't start Winsock" , L"Benachrichtigung", MB_ICONERROR);
break;
case 11:
MessageBox(hWnd, L"Can't create socket", L"Benachrichtigung", MB_ICONERROR);
break;
case 12:
MessageBox(hWnd, L"Can't connect to server", L"Benachrichtigung", MB_ICONERROR);
break;
case 13:
MessageBox(hWnd, L"Socket Error!", L"Benachrichtigung", MB_ICONERROR);
break;
}
}
break;
case WM_CTLCOLOREDIT:
if (hWndEdit == (HWND)lParam) {
HDC hdc = (HDC)wParam;
SetBkColor(hdc, RGB(211, 211, 211));
//SetTextColor(hdc, RGB(211, 211, 211)); // For diffrent color of latters
SetDCBrushColor(hdc, RGB(211, 211, 211));
return (LRESULT)GetStockObject(DC_BRUSH);
}
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 20, 20, L"Gewünschte Taster Zyklen Eingeben", strlen("Gewünschte Taster Zyklen Eingeben"));
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
HWND hButton;
WNDCLASS wc;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MessageHandler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"WINAPITest";
assert(RegisterClass(&wc));
hWnd = CreateWindow(L"WINAPITest", L"WinAPI Tutorial", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, 0, 0, hInstance, 0);
hButton = CreateWindow(L"button", L"OK", WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 40, 100, 200, 50, hWnd, (HMENU)10, hInstance, 0);
hWndEdit = CreateWindow(L"edit", NULL, WS_TABSTOP | WS_CHILD | WS_BORDER | WS_VISIBLE, 40, 48, 200, 50, hWnd, 0, 0, 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (true) {
BOOL result = GetMessage(&msg, 0, 0, 0);
if (result > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
return result;
}
}
}
Two bugs:
As I called out in the comments, you are forgetting to invoke EndPaint and have a missing break statement. Fixing that and cleaning up your code so you don't have to duplicate the string:
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
const wchar_t* message = L"Gewünschte Taster Zyklen Eingeben";
TextOut(hdc, 20, 20, message, wcslen(message));
EndPaint(hWnd, &ps);
return 0; // THIS LINE ADDED
Bug #2 is that you are forgetting to invoke RegisterClass on your WNDCLASSEX structure. Also, it's usually a good idea to default initialize that struct (to zeros) in case you missed a field or wanted to skip it.
wc = {}; // zero-init THIS LINE ADDED
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MessageHandler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"WINAPITest";
RegisterClass(&wc); // THIS LINE ADDED
After I removed the TCP Client stuff, I got your program to somewhat work:
And for some style points, I cleaned up this:
while (true) {
BOOL result = GetMessage(&msg, 0, 0, 0);
if (result > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
return result;
}
}
To simply be this:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;

separate thread to prevent progress bar from 'freezing' in c++

I built a simplest progress bar which shows the progress of my png frame generation. Here is the process
BOOL myProc(HWND hwndParent, HINSTANCE hInst) {
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hwndParent, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR) NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hwndParent, (HMENU) 0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
for (int i = 0; i < N + 1; i++) {
int frame = create_pngInt(i);
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hwndPB);
DestroyWindow(hwndParent);
return TRUE;
}
I want my window to host just this progress bar. When the loop in myProc is done, the host window should be destroyed.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
std::thread q(myProc, hMainWindow, hInst);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, the window hMainWindow is not destroyed (!) and the process myProc doesn't terminate by itself (after the loop in myProc is comlete).
It seems I don't understand something important.
I checked. If I don't create a separate thread but just run myProc in WinMain, the window hosting the progress bar destroyed after myProc returns. And this is precisely what I want. But the progress bar freezes after several seconds(. That is why I need a separate thread.
Following your remarks I modified the code like this:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q(myProc, hMainWindow, hInst, hwndPB);
MSG msg = { 0 };
while (GetMessage(&msg, hMainWindow, NULL, NULL))
{
if (msg.message == WM_QUIT) {
DestroyWindow(hMainWindow);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
However, I know that I haven't handled WM_QUIT event properly, and the whole thing is not destroyed. Could you please, elaborate just a little bit more and if the rest of the code is ok?
The thread which calls CreateWindowEx needs to be the one executing the GetMessage loop.
It won't get destroyed, as there is nothing processing the events and messages for it, including the WM_DESTROY message.
Keep your window creation in your main thread (and that thread only!), and use only PostMessage / SendMessage to send update events and finally a destroy message to the window owned by the main thread.
Ultimately handle a WM_DESTROY to your main window with PostQuitMessage and your are done.
In full:
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE PrevInst, LPSTR args, int ncmdshow) {
RECT rect;
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"GenPng";
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = CreateSolidBrush(0x00171c00);
wc.hIcon = hIcon;
if (!RegisterClassW(&wc))
return -1;
hMainWindow = CreateWindowW(
L"GenPng", L"Generating pngs", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
200,
100, 300, 58, NULL, NULL, NULL, NULL
);
SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
RECT rcClient;
int cyVScroll;
HWND hwndPB;
DWORD cb;
GetClientRect(hMainWindow, &rcClient);
cyVScroll = GetSystemMetrics(SM_CYVSCROLL);
hwndPB = CreateWindowEx(
0, PROGRESS_CLASS, (LPTSTR)NULL,
WS_CHILD | WS_VISIBLE, rcClient.left,
rcClient.bottom - cyVScroll,
rcClient.right, cyVScroll,
hMainWindow, (HMENU)0, hInst, NULL
);
int N = lastFrame;
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, N));
SendMessage(hwndPB, PBM_SETSTEP, (WPARAM)1, 0);
std::thread q([hMainWindow, hInst, hwndPB, N]() {
for (int i = 0; i < N + 1; i++) {
SendMessage(hwndPB, PBM_STEPIT, 0, 0);
}
DestroyWindow(hMainWindow);
});
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
if (msg.message == WM_DESTROY) {
PostQuitMessage(0);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
q.join();
// Exit code from PostQuitMessage() is still in msg.param
return msg.param;
}

Adding Different Components in Tab Control Win32

I am creating a Windows desktop application using win32 api in visual studio 2019. I know there are many other options avialable to build UI like MFC, XAMAL and C#, but i needed to build it in win32. I have learnt some basics in win32 api but recently i was working on tabControll and there i got an issue or i missed some thing. I am creating two tabs and want to add different content withing them. My current code is working and creating the tabs but it is adding same content in both tabs. How should i define each tab's content differently.
void createTabView(HWND hWnd) {
RECT rcClient;
INITCOMMONCONTROLSEX icex;
static HWND hwndTab_1_1_1;
HWND hwndTab;
TCITEM tie;
int i;
TCHAR achTemp[256];
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
GetClientRect(hWnd, &rcClient);
hwndTab = CreateWindow(WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hWnd, NULL, hInst, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 1, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 2, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
HWND hwndStatic = CreateWindow(WC_STATIC, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInst, // g_hInst is the global instance handle
NULL);}
The tab control triggers the WM_NOTIFY signal when the tab page is switched, so as long as we process the WM_NOTIFY message, we can control the tab control message.
In the WM_NOTIFY message:
wParam: a control ID that identifies the WM_NOTIFY message sent.
lParam: a pointer to the NMHDR structure.
Therefore, we can determine the notification code sent by the Tab control in the WM_NOTIFY message processing program by judging the code value in the NMHDR structure.
We can use TCN_SELCHANGE to handle the operation when the Tab tab changes, and use TabCtrl_GetCurSel to get the index of the current tab and define the content of the current tab.
Here is the sample:
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
static HINSTANCE hInstance;
static HWND hwndTab = 0 , hwndStatic = 0;
TCITEM tie;
RECT rcClient;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
TCHAR tabLBL1[256];
GetClientRect(hwnd, &rcClient);
switch (message)
{
case WM_CREATE:
{
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hwndTab = CreateWindow(WC_TABCONTROL, "",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hwnd, NULL, hInstance, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
wsprintf(tabLBL1, "tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, "tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
hwndStatic = CreateWindow(WC_STATIC, "",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic,TRUE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
{
int tabID = TabCtrl_GetCurSel(hwndTab);
switch (tabID)
{
case 0:
ShowWindow(hwndStatic, TRUE);
break;
case 1:
ShowWindow(hwndStatic, FALSE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Not sure if this is the solution, but the iItem parameter to TabCtrl_InsertItem is zero-based. Try:
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 1, &tie);
Also (and I'm not sure if this is relevant), you look like you intended to call InitCommonControlsEx in your code but fail to do so.

How to Stop C/C++ WINAPI Window Showing on all Desktops?

I am writing a C/C++ windows app which calls CreateWindow as follows:
HWND hWnd = CreateWindow(pszClassName, title_.c_str(), WS_OVERLAPPED | WS_VISIBLE | WS_POPUP | WS_SIZEBOX, 50, 50, 400, 100, NULL, NULL, hInst, this);
Nothing particularly complex about it, however, it is appearing on every desktop on my computer when I switch from one desktop to another with CTRL-WIN < or >.
How do you make window you create in an app remain only on the desktop that you created it on?
I am compiling this app in 64bit and running it on Windows 10.
Code:
Global:
WNDCLASSEX wc;
Window procedure:
case WM_KEYDOWN:
if(wParam == VK_F11)
{
wc.style = HWND_DESKTOP;//The window is child
//of desktop
}
break;
WinMain:
LPCSTR windowName = "Answer on StackOwerflow";
MSG messages;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "The classname";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
wc.lpszClassName,
windowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd);
UpdateWindow(hWnd);
while(GetMessage(&messages, NULL, 0, 0) > 0)
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return 0;

C++(WINAPI - WIN32) Second edit box can't read the input value

I have two edit boxes. The first edit box read the input but the second edit box for some reason gives me an empty value. I have checked the windows handle value which is not NULL. What am I supposed to do because I am very very new with GUI programming. I hope you guys can help.
#include <windows.h>
#include "GUI.h"
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
//#include "main.h"
const char g_szClassName[] = "myWindowClass";
HWND btObj[1], lblObj, lbl2Obj, hEdit1, hEdit2;
void CreateObjects(HWND hWnd)
{
//Buttons
btObj[0] = CreateWindow(TEXT("button"), //lpClassName = type of window to create
TEXT("Process"), //lpWindowName = Name that appears on the button
WS_VISIBLE | WS_CHILD, //dwStyle = Window style flags
140, 90, // x and y coordinates of the button in pixels
105, 33, //width and height of the button in pixels
hWnd, //hWndParent = handle of the parent or main window
(HMENU)1, //Menu item ID = 1
NULL, NULL); //Set the last 2 params as null
//Labels
lblObj = CreateWindow(TEXT("edit"),
TEXT("File Input: "),
WS_VISIBLE | WS_CHILD,
16, 16,
490, 25,
hWnd,
(HMENU)2,
NULL, NULL);
//Textbox
hEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
100, 16,
200, 25,
hWnd,
(HMENU)IDC_MAIN_INPUT,
GetModuleHandle(NULL), NULL);
//Labels
lbl2Obj = CreateWindow(TEXT("edit"),
TEXT("File Output: "),
WS_VISIBLE | WS_CHILD,
16, 55,
510, 40,
hWnd,
(HMENU)4,
NULL, NULL);
//Textbox number 2
hEdit2 = CreateWindowEx(WS_EX_CLIENTEDGE,
"EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
100, 55,
200, 25,
hWnd,
(HMENU)IDC_MAIN_OUTPUT,
GetModuleHandle(NULL), NULL);
}
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_MAIN_BUTTON:
//HWND inputFile, outputFile;
TCHAR inFile[30];
TCHAR outFile[30];
//TEXTBOX 1
HWND hEditWnd;
hEditWnd = GetDlgItem(hwnd, IDC_MAIN_INPUT);
HWND hEditWnd2;
hEditWnd2 = GetDlgItem(hwnd, IDC_MAIN_OUTPUT);
GetWindowText(hEditWnd,inFile, 30);
SetDlgItemTextA(hwnd, IDC_MAIN_INPUT, inFile);
if (hwnd == NULL)
{
MessageBox(NULL, "This hwnd is NULL Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
else
{
MessageBox(NULL, "This hwnd has some value", "Error!", MB_ICONEXCLAMATION | MB_OK);
}
SetFocus (hEdit2);
GetWindowText(hEditWnd2,outFile, 30);
SetDlgItemTextA(hwnd, IDC_MAIN_OUTPUT, outFile);
MessageBox(NULL, inFile, "TESTING", MB_OK);
MessageBox(NULL, outFile, "TESTING", MB_OK);
}
break;
case WM_CREATE:
CreateObjects(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"CSV Converter",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
390, 200,
NULL, NULL,
hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
hEditWnd = GetDlgItem(hwnd, IDC_MAIN_INPUT);
...
GetWindowText(hEditWnd,inFile, 30);
SetDlgItemTextA(hwnd, IDC_MAIN_INPUT, inFile);
You are retreiving the inFile value from the IDC_MAIN_INPUT control, and then assigning the inFile value back to the same IDC_MAIN_INPUT control.
hEditWnd2 = GetDlgItem(hwnd, IDC_MAIN_OUTPUT);
...
GetWindowText(hEditWnd2,outFile, 30);
SetDlgItemTextA(hwnd, IDC_MAIN_OUTPUT, outFile);
You are retreiving the outFile value from the IDC_MAIN_OUTPUT control, and then assigning the outFile value back to the same IDC_MAIN_OUTPUT control.
The end result: you don't see any change in the UI, because you did not actually change anything!