Repaint window problems - c++

#include "stdafx.h"
// Mario Headers
#include "GameMain.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Mario global variables =================
CGameMain* gGameMain;
HWND hWnd;
PAINTSTRUCT ps;
// ========================================
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
// My unprocess function =====================================
void OnCreate(HWND hWnd)
{
}
void OnKeyUp(WPARAM wParam)
{
switch (wParam) {
case VK_LEFT:
gGameMain->KeyReleased(LEFT);
break;
case VK_UP:
gGameMain->KeyReleased(UP);
break;
case VK_RIGHT:
gGameMain->KeyReleased(RIGHT);
break;
case VK_DOWN:
gGameMain->KeyReleased(DOWN);
break;
}
}
void OnKeyDown(HWND hWnd,WPARAM wParam)
{
switch (wParam) {
case VK_LEFT:
gGameMain->KeyPressed(LEFT);
break;
case VK_UP:
gGameMain->KeyPressed(UP);
break;
case VK_RIGHT:
gGameMain->KeyPressed(RIGHT);
break;
case VK_DOWN:
gGameMain->KeyPressed(DOWN);
break;
}
}
void OnPaint(HWND hWnd)
{
HDC hdc = BeginPaint(hWnd,&ps);
RECT rect;
GetClientRect(hWnd,&rect);
HDC hdcDouble = CreateCompatibleDC(hdc);
HBITMAP hdcBitmap = CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
HBITMAP bmOld = (HBITMAP)SelectObject(hdcDouble, hdcBitmap);
gGameMain->SetHDC(&hdcDouble);
gGameMain->SendMessage(MESSAGE_PAINT);
BitBlt(hdc,0,0,rect.right,rect.bottom,hdcDouble,0,0,SRCCOPY);
SelectObject(hdcDouble,bmOld);
DeleteDC(hdcDouble);
DeleteObject(hdcBitmap);
DeleteDC(hdc);
}
void OnDestroy()
{
gGameMain->isPlaying = false;
EndPaint(hWnd,&ps);
}
// My unprocess function =====================================
ATOM MyRegisterClass(HINSTANCE hInstance)
{
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(hInstance, MAKEINTRESOURCE(IDI_GDIMARIO));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_GDIMARIO);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, 0, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// ---------------- Start gdiplus ------------------
GdiplusStartup(&gdiToken,&gdiStartInput,NULL);
// -------------------------------------------------
// Init GameMain
gGameMain = new CGameMain();
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
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_KEYDOWN:
OnKeyDown(hWnd,wParam);
break;
case WM_KEYUP:
OnKeyUp(wParam);
break;
case WM_CREATE:
OnCreate(hWnd);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DESTROY:
OnDestroy();
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;
}
break;
}
return (INT_PTR)FALSE;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_GDIMARIO, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIMARIO));
// Main message loop:
// GameLoop
PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
while (gGameMain->isPlaying)
{
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (gGameMain->enterNextState) {
gGameMain->SendMessage(MESSAGE_ENTER);
gGameMain->enterNextState = false;
}
gGameMain->SendMessage(MESSAGE_UPDATE);
InvalidateRect(hWnd,NULL,FALSE);
/*if (gGameMain->exitCurrentState) {
gGameMain->SendMessage(MESSAGE_EXIT);
gGameMain->enterNextState = true;
gGameMain->exitCurrentState = false;
}*/
::Sleep(gGameMain->timer);
// Do your game stuff here
}
GdiplusShutdown(gdiToken); // Shut down gdiplus token
return (int) msg.wParam;
}
I use InvalidateRect(hWnd,NULL,FALSE); for repaint window, but the problem I met is when I repaint without any changes in Game struct .
First it paints my logo well, the second time ( just call InvalidateRect(hWnd,NULL,FALSE); without gGameMain->SendMessage(MESSAGE_ENTER); which is init some variables for painting .
Thanks for reading this :)

You're calling BeginPaint() in each wm_paint message, but there's no corresponding call to EndPaint() in the wm_paint message handler. Each BeginPaint() must be matched with a corresponding EndPaint(). Your EndPaint() call in OnDestroy is useless.
Also, don't delete the DC returned by BeginPaint(). It is borrowed, not owned.
Other notes: Try to avoid allocating a new bitmap on every wm_paint message. Allocate the bitmap when the window changes size, and hold onto it to be reused by multiple wm_paint passes.
Also note that you're not optimizing the draw to draw only what has been invalidated in the clip rect. You're drawing everything, blitting everything, and relying on GDI to only take the small portion of the bitmap that is actually in the clip rect. This will become a performance issue as the size of your window/bitmap increases and the number of objects/sprites you have running around on the screen increases. You should only draw things that are visible and within the cliprect.

Related

Visual Studio 2019 C++ Desktop application; How do I make a child window?

I successfully created an app with a main window, a title bar, and a menu structure. Now I want to create a child window within the borders of the main window to handle one of the menu options. I did at least create the callback structure for the child window, whose function is "Connect."
In the interest of creating an infinitely flexible development protocol, MS has implemented a regime in which "this is an alias for that," and "this is a new version of an old function that does something better than in Windows 7." I need, please, the seven-year-old's instruction, "Put this line here." I promise that once the ball starts rolling, I'll see that it gets to the bottom of the hill.
Specifically: (a) Where and how do I register the class for the new window, as it seems to fit this framework?
(b) Where does the new CreateWindowW function go?
/**
* #file AD4951.cpp
* #brief Application for PC that polls Primera devices
* #author Robert Hadow
* #date April 2021
* #par Revision History:
*
*
**/
// AD4951.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "AD4951.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK Connect(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_AD4951, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_AD4951));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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(hInstance, MAKEINTRESOURCE(IDI_AD4951));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_AD4951);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_CONNECT: // Robert
break;
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;
}
// 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;
}
break;
}
return (INT_PTR)FALSE;
}
// Message handler for connect window.
INT_PTR CALLBACK Connect(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;
}
break;
}
return (INT_PTR)FALSE;
}
Where and how do I register the class for the new window
You can register the window class for the child window at anytime during program initialization. So inside the MyRegisterClass function is a perfectly fine place to do it.
Where does the new CreateWindowW function go?
Best choice: you can simply invoke CreateWindow for the child windows in WM_CREATE of your main window.
Or you can invoke CreateWindow outside your child's windows proc immediately after the original CreateWindow call returns for the parent window.
Find a used copy of the Petzold Book for classic Win32 programming.

DwmDefWindowProc always returns false

I'm having trouble utilizing Win API's DwmDefWindowProc. It always returning false, even when DWM is enabled.
I'm sending a WM_NCHITTEST message to the window procedure to detect the action of the mouse position but it's not giving me accurate results (due to DWM being enabled and me needing to call DwmDefWindowProc beforehand).
I'm using a Windows 10 (Ver. 2004) machine and I have tested the same behavior on my Windows 7 virtual machine. If I change the combability of the executable to launch as Windows XP (Disabling DWM, I'm getting the expected behavior).
Otherwise, the information I'm getting back from WM_NCHITTEST is incorrect as the right side of the maximize button returns the expected HTMAXBUTTON while the left side of it returns HTREDUCE.
Reproducing the issue with the Windows Desktop Application template (found below). If you have DWM enabled (Most Windows 10 users would), the maximize button no longer works properly. If run the program in Visual Studio and select the Output tab, you'll see that when you hover to the left (green border in the picture below) of the maximize button you will get a HTMINBUTTON message while if you hover to the right (red border in the picture below) you will get the expected HTMAXBUTTON message.
Here's the sample code
// SimpleWindow.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "SimpleWindow.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
/* New Stuff */
#include <dwmapi.h>
#pragma comment(lib, "Dwmapi.lib")
void DWMExample(HWND hWnd, unsigned int msg, unsigned int wParam, int lParam);
LRESULT ProcessNCHitTest(HWND hWnd, int lParam);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_SIMPLEWINDOW, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow)) {
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SIMPLEWINDOW));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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(hInstance, MAKEINTRESOURCE(IDI_SIMPLEWINDOW));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SIMPLEWINDOW);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd) {
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
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:
{
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;
}
/* New Stuff */
if (message == WM_NCHITTEST) {
return ProcessNCHitTest(hWnd, lParam);
}
DWMExample(hWnd, message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
void DWMExample(const HWND hWnd, const unsigned int msg, const unsigned int wParam, const int lParam)
{
switch (msg) {
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
{
const auto ht = SendMessageA(hWnd, WM_NCHITTEST, wParam, lParam);
switch (ht) {
case HTBORDER:
OutputDebugStringA("HTBORDER\n");
break;
case HTBOTTOM:
OutputDebugStringA("HTBOTTOM\n");
break;
case HTBOTTOMLEFT:
OutputDebugStringA("HTBOTTOMLEFT\n");
break;
case HTBOTTOMRIGHT:
OutputDebugStringA("HTBOTTOMRIGHT\n");
break;
case HTCAPTION:
OutputDebugStringA("HTCAPTION\n");
break;
case HTCLIENT:
OutputDebugStringA("HTCLIENT\n");
break;
case HTCLOSE:
OutputDebugStringA("HTCLOSE\n");
break;
case HTERROR:
OutputDebugStringA("HTERROR\n");
break;
case HTGROWBOX:
OutputDebugStringA("HTGROWBOX\n");
break;
case HTHELP:
OutputDebugStringA("HTHELP\n");
break;
case HTHSCROLL:
OutputDebugStringA("HTHSCROLL\n");
break;
case HTLEFT:
OutputDebugStringA("HTLEFT\n");
break;
case HTMENU:
OutputDebugStringA("HTMENU\n");
break;
case HTMAXBUTTON:
OutputDebugStringA("HTMAXBUTTON\n");
break;
case HTMINBUTTON:
OutputDebugStringA("HTMINBUTTON\n");
break;
case HTNOWHERE:
OutputDebugStringA("HTNOWHERE\n");
break;
// case HTREDUCE:
// OutputDebugStringA("HTREDUCE\n");
// break;
case HTRIGHT:
OutputDebugStringA("HTRIGHT\n");
break;
// case HTSIZE:
// OutputDebugStringA("HTSIZE\n");
// break;
case HTSYSMENU:
OutputDebugStringA("HTSYSMENU\n");
break;
case HTTOP:
OutputDebugStringA("HTTOP\n");
break;
case HTTOPLEFT:
OutputDebugStringA("HTTOPLEFT\n");
break;
case HTTOPRIGHT:
OutputDebugStringA("HTTOPRIGHT\n");
break;
case HTTRANSPARENT:
OutputDebugStringA("HTTRANSPARENT\n");
break;
case HTVSCROLL:
OutputDebugStringA("HTVSCROLL\n");
break;
// case HTZOOM:
// OutputDebugStringA("HTZOOM\n");
// break;
}
}
break;
}
}
LRESULT ProcessNCHitTest(const HWND hWnd, const int lParam)
{
BOOL isDWMEnabled = false;
if (FAILED(DwmIsCompositionEnabled(&isDWMEnabled))) {
return DefWindowProcA(hWnd, WM_NCHITTEST, 0, lParam);
}
if (!isDWMEnabled) {
return DefWindowProcA(hWnd, WM_NCHITTEST, 0, lParam);
}
LRESULT result = 0;
if (!DwmDefWindowProc(hWnd, WM_NCHITTEST, 0, lParam, &result)) {
return DefWindowProcA(hWnd, WM_NCHITTEST, 0, lParam);
}
return result;
}
// 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;
}
break;
}
return (INT_PTR)FALSE;
}
Any idea where I'm going wrong? Any help would be appreciated!

WM_DEVICECHANGE lParam is null

I want to detect the insertion and removing of any USB drive in my computer. I am not experienced in Windows GUI programming, and usually use Qt, but I had to use the Win32 API this time.
The problem is that lParam is always null.
I read that I need to use RegisterDeviceNotification(), but I used it and even with DEVICE_NOTIFY_ALL_INTERFACE_CLASSES, lParam is always null, however the function succeeds.
This is my code. Most of it I took from a Win32 app template from Visual Studio 2015:
#define MAX_LOADSTRING 100
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_USBSPREAD, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCE(IDC_USBSPREAD));
MSG msg;
// Main message loop:
while (GetMessageW(&msg, nullptr, 0, 0))
{
if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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(hInstance, MAKEINTRESOURCE(IDI_USBSPREAD));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_USBSPREAD);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72,
0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 };
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, (void*)&WceusbshGUID);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DEVICECHANGE:
{
//if (!lParam) break;
PDEV_BROADCAST_HDR hdr = (PDEV_BROADCAST_HDR)lParam;
if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE_W device = (PDEV_BROADCAST_DEVICEINTERFACE_W)hdr;
if (hdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
if (wParam == DBT_DEVICEARRIVAL) {
MessageBoxA(0, "a usb was inserted", "", 0);
}
else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
MessageBoxA(0, "a usb was removed", "", 0);
}
}
}
}
case WM_NCCREATE: // before window creation
return true;
break;
case WM_CREATE :
{
LPCREATESTRUCT params = (LPCREATESTRUCT)lParam;
GUID InterfaceClassGuid = *((GUID*)params->lpCreateParams);
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = InterfaceClassGuid;
HDEVNOTIFY dev_notify = RegisterDeviceNotification(hWnd, &NotificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE);
if (!dev_notify) {
string error = "failed with error : ";
error += GetLastError();
MessageBoxA(0, error.c_str(), 0, 0);
}
else {
MessageBoxA(0, "succeeded", "", 0);
}
}
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:
{
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;
}
// 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;
}
break;
}
return (INT_PTR)FALSE;
}
You need to check wParam first and then figure out what to expect from lParam (it can be NULL in some situations). Also there is a break missing after case.
case WM_DEVICECHANGE:
{
switch(wParam)
{
case DBT_DEVICEARRIVAL:
{
assert(lParam);
::MessageBoxW(NULL, L"a usb was inserted", L"", MB_OK);
::PDEV_BROADCAST_HDR hdr{reinterpret_cast<::PDEV_BROADCAST_HDR>(lParam)};
if(hdr)
{
// check info...
}
break;
}
default:
{
// do nothing...
break;
}
} // switch(wParam)
break;
}

How to prevent Win32 app after closing one window the others windows become inactive

So my task is to create 5 child windows and when key is pressed close windows in other order. But I have a problem, when I close first 2 windows the other ones become inactive so I have to click on it so it could be focused window, but how can I prevent other windows to become inactive?
#include "stdafx.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
int windowsCount = 1;
WCHAR buffer[5];
HWND windows[5];
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
srand(unsigned(time(NULL)));
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_OOP10, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OOP10));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEXW 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(hInstance, MAKEINTRESOURCE(IDI_OOP10));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_OOP10);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, L"Main Window", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
SetClassLong(hWnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256)));
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
windows[0] = hWnd;
return TRUE;
}
BOOL CreateChildWindow(HWND hWnd) {
_itoa(windowsCount + 1, (char*)buffer, 10);
SetClassLong(hWnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256)));
HWND childWnd = CreateWindow(szWindowClass, buffer, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, windows[windowsCount - 1], nullptr, hInst, nullptr);
if (!childWnd)
return FALSE;
ShowWindow(childWnd, SW_SHOWDEFAULT);
UpdateWindow(childWnd);
windows[windowsCount++] = childWnd;
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_LBUTTONUP:
{
if (windowsCount < 5) {
if (!CreateChildWindow(hWnd))
return FALSE;
}
}
break;
case WM_CLOSE:
{
if (IDOK == MessageBox(hWnd, L"Are you sure you want to quit?", L"You are leaving the program", MB_OKCANCEL | MB_ICONINFORMATION | MB_DEFBUTTON2)) {
if (windowsCount == 1) {
DestroyWindow(windows[--windowsCount]);
PostQuitMessage(NULL);
break;
}
else
DestroyWindow(windows[--windowsCount]);
}
}
break;
case WM_RBUTTONUP:
SetWindowText(hWnd, L"Changed title!");
break;
case WM_KEYDOWN: {
if (windowsCount == 1) {
DestroyWindow(windows[--windowsCount]);
PostQuitMessage(NULL);
break;
}
else
DestroyWindow(windows[--windowsCount]);
}
break;
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:
{
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;
}
// 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;
}
break;
}
return (INT_PTR)FALSE;
}
This should be part of your application logic. Add event handler to the WM_CLOSE message to all your windows and set focus to the appropriate window that is not closed yet.
Windows cannot decide this for you.

win32api SendMessage wont work outside of WM_CREATE

So, i was working on a "larger" project, and suddenly got strange issues with a simple sendmessage command.. So i created a new project, That just creates a edit control, and a timer. Everytime the timer ticks it should put out "test" to the edit control. But it never happens..
Ive tried the timer with a messagebox, and it works. Also the sendmessage work, if i put it in WM_CREATE.. Why is this?
// 785tyughj.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "785tyughj.h"
#define MAX_LOADSTRING 100
#define ID_FLSPEED 1
#define ID_TIMER 2
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND FLSPEED;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MY785TYUGHJ, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY785TYUGHJ));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
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(hInstance, MAKEINTRESOURCE(IDI_MY785TYUGHJ));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MY785TYUGHJ);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
{
HWND FLSPEED=CreateWindowEx(WS_EX_CLIENTEDGE,
L"EDIT",
L"speed",
WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|ES_AUTOHSCROLL,
50,
50,
125,
25,
hWnd,
(HMENU)ID_FLSPEED,
GetModuleHandle(NULL),
NULL);
SetTimer (hWnd,ID_TIMER,1000,NULL);
}
case WM_TIMER:
{
SendMessageA(FLSPEED,WM_SETTEXT,NULL,(LPARAM)"test");
break;
}
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_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
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;
}
break;
}
return (INT_PTR)FALSE;
}
The following line is the problem:
HWND FLSPEED=CreateWindowEx(WS_EX_CLIENTEDGE,
L"EDIT",
L"speed",
WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|ES_AUTOHSCROLL,
50,
50,
125,
25,
hWnd,
(HMENU)ID_FLSPEED,
GetModuleHandle(NULL),
NULL);
In that line you are creating a new local FLSPEED that masks the global FLSPEED. To fix that get rid of the HWND so that you are not declaring a new variable and that you actually change the value of the global.
FLSPEED=CreateWindowEx(WS_EX_CLIENTEDGE,
L"EDIT",
L"speed",
WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOVSCROLL|ES_AUTOHSCROLL,
50,
50,
125,
25,
hWnd,
(HMENU)ID_FLSPEED,
GetModuleHandle(NULL),
NULL);