separate thread to prevent progress bar from 'freezing' in c++ - 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;
}

Related

Window redraw breaks after a few seconds

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.

WIN32:C++, why is calling the Messagebox function on WM_CLOSE The program is freezing

I'm learning about creating a Windows desktop application using Visual C++.
I am creating a simple window that does nothing, and when I press the close button, I wanted to display a message box to confirm that I really want to close it before I close the window.
So I tried to do this using the Messagebox function when I got the WM_CLOSE message, but for some reason the program froze and wouldn't close.
I'm sorry, but can someone help me out?
The source is as follows. Thank you for your help.
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
TCHAR szClassName[] = TEXT("winapp");
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) {
MSG msg;
BOOL bRet;
if(!InitApp(hCurInst))
return FALSE;
if (!InitInstance(hCurInst, nCmdShow))
return FALSE;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
MessageBox(NULL, TEXT("GetMessageエラー"), TEXT("Error"), MB_OK);
break;
}
else {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
ATOM InitApp(HINSTANCE hInst) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(
NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIconSm = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
return (RegisterClassEx(&wc));
}
BOOL InitInstance(HINSTANCE hInst, int nCmdShow) {
HWND hWnd;
hWnd = CreateWindow(
szClassName,
TEXT("Winapp"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
int id;
switch (msg){
case WM_CLOSE:
id = MessageBox(hWnd,TEXT("終了してもよろしいですか?"),TEXT("終了確認"),MB_YESNO | MB_ICONQUESTION);
if(id==IDYES){
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
Try explicit use of unicode in your program. for exsmple using MessageBoxW instead of MessageBox and L"終了してもよろしいですか?" instead of TEXT("終了してもよろしいですか?") and change your windowproc a bit:
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
TCHAR szClassName[] = TEXT("winapp");
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) {
MSG msg;
BOOL bRet;
if(!InitApp(hCurInst))
return FALSE;
if (!InitInstance(hCurInst, nCmdShow))
return FALSE;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
MessageBoxW(NULL, L"GetMessageエラー", L"Error", MB_OK);
break;
}
else {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
ATOM InitApp(HINSTANCE hInst) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(
NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIconSm = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
return (RegisterClassEx(&wc));
}
BOOL InitInstance(HINSTANCE hInst, int nCmdShow) {
HWND hWnd;
hWnd = CreateWindow(
szClassName,
TEXT("Winapp"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
int id;
switch (msg){
case WM_CLOSE:
id = MessageBoxW(hWnd,L"終了してもよろしいですか?", L"終了確認",MB_YESNO | MB_ICONQUESTION);
if(id==IDYES){
DestroyWindow(hWnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return (DefWindowProc(hWnd, msg, wp, lp));
}
If you try to press the close button, but the MessageBox does not pop up. Try to press the ALT key to see if it pops up. I suggest you handle the WM_PAINT message to ensure that the drawing message is processed.
Code:
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
TCHAR szClassName[] = TEXT("winapp");
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) {
MSG msg;
BOOL bRet;
if (!InitApp(hCurInst))
return FALSE;
if (!InitInstance(hCurInst, nCmdShow))
return FALSE;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
MessageBox(NULL, TEXT("GetMessageエラー"), TEXT("Error"), MB_OK);
break;
}
else {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
ATOM InitApp(HINSTANCE hInst) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(
NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIconSm = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
return (RegisterClassEx(&wc));
}
BOOL InitInstance(HINSTANCE hInst, int nCmdShow) {
HWND hWnd;
hWnd = CreateWindow(
szClassName,
TEXT("Winapp"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
int id;
PAINTSTRUCT ps;
switch (msg) {
case WM_PAINT:
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_CLOSE:
id = MessageBox(hWnd, TEXT("終了してもよろしいですか?"), TEXT("終了確認"), MB_YESNO | MB_ICONQUESTION);
if (id == IDYES) {
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
More reference:Why would a message box be not displaying?

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.

ChoosePixelFormat Access violation reading location

I'm trying to create a simple OpenGL context but the program crashes on ChoosePixelFormat with the error "Unhandled exception at 0x779CE0E6 (ntdll.dll) in OpenGL.exe: 0xC0000005: Access violation reading location 0x00000044." This same code used to work a while back but for some reason doesn't work anymore. I tried updating my graphics drivers to no avail. If it matters, I have a 64-bit Windows 7 Home premium, a GeForce 570 and a Intel Core i7-2600 3,40 GHz.
This is the code I use in the order of execution to the point it crashes:
GLEngine gl(WndProc); //WndProc just calls DefWindowProc
- calls ->
GLEngine::GLEngine(WNDPROC wndproc) { //Initialize class
hRC = NULL;
hDC = NULL;
hWnd = NULL;
fullscreen = false;
active = false;
proc = wndproc;
itemsLength = 0;
currentActive = this;
success = true;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) {
gl.CreateGL2Window("Test", 1300, 900, 8, false, true);
- calls ->
bool GLEngine::CreateGL2Window(char* title, int width, int height, bool internalflag) {
GLuint pixelFormat;
WNDCLASSEX wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT windowRect;
windowRect.left = (long)0;
windowRect.right = (long)width;
windowRect.top = (long)0;
windowRect.bottom = (long)height;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance; //hInstance is NULL here, should it be something else?
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = _T("OpenGL");
wc.hIconSm = NULL;
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, _T("Failed To Register The Window Class."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
hInstance = wc.hInstance; //hInstance isn't NULL anymore
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle);
if(!(hWnd = CreateWindowEx(dwExStyle, _T("OpenGL"),
(wchar_t*)title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
0, 0,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
NULL,
NULL,
hInstance,
NULL))) {
DestroyGLWindow();
MessageBox(NULL, _T("Window Creation Error."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
if(!(hDC = GetDC(hWnd))) {
DestroyGLWindow();
MessageBox(NULL, _T("Can't Create A GL Device Context."), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
return false;
}
PIXELFORMATDESCRIPTOR pfd2 = { sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
32,
8,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
if(!(pixelFormat = ChoosePixelFormat(hDC, &pfd2)) {
GLEngine is in a dll. It shouldn't matter but the information can't hurt.
Did you get address of function with GetProcAddress? Faulty drivers can cause crash on this too. ChoosePixelFormat may be implemented and exported driver-side, but it might be not exported, then system procedure should be used. exported one may or may not filling descriptor structure, depending on implementation, so you need to call DescribePixelFormat.

Where to place destroying function

Holla.
I have one question about placing 'destroying function'.
Globals:
HWND g_hInvisible = NULL;
HINSTANCE g_hInstance = NULL;
Code for WinMain:
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR lpCmdLine,INT nShows)
{
MSG msg = {0};
WNDCLASSEXW wcMain = {0};
wcMain.cbSize = sizeof(WNDCLASSEXW);
wcMain.style = CS_SAVEBITS;
wcMain.lpfnWndProc = MainWindowProc;
wcMain.hInstance = g_hInstance;
wcMain.lpszClassName = L"MAINCLASS";
RegisterClassEx(&wcMain);
HWND hMainWindow = CreateWindowEx(0, L"MAINCLASS", L"Main Class Window", WS_OVERLAPPEDWINDOW, 100, 100, 100, 100, NULL, NULL, g_hInstance, NULL);
InvisibleWindowInit();
InvisibleWindowTerminate(); // <<< PLACE HERE ?
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
InvisibleWindowTerminate(); // <<< OR PLACE HERE ?
return (int) msg.wParam;
}
Code for InvisibleWindowInit:
BOOL InvisibleWindowInit()
{
WNDCLASSEXW wcInvisible = {0};
wcInvisible.cbSize = sizeof(WNDCLASSEXW);
wcInvisible.style = CS_SAVEBITS;
wcInvisible.lpfnWndProc = InvisibleWindowProc;
wcInvisible.hInstance = g_hInstance;
wcInvisible.lpszClassName = L"INVISIBLE";
RegisterClassEx(&wcInvisible);
g_hInvisible = CreateWindowEx(0, L"INVISIBLE", L"INVISIBLE", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL);
if (g_hInvisible == NULL)
{
dError = GetLastError();
return FALSE;
}
return TRUE;
}
Code for InvisibleWindowTerminate:
VOID InvisibleWindowTerminate()
{
DestroyWindow(hInvisible);
g_hInvisible = NULL;
}
I want to in another piece of code call InvisibleWindowTerminate
So where is better place, before message loop or after ?
Thank you.