Child Windows not showing - c++

ATOM MyRegisterChildClass(void)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = ChildProc;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8);
wcex.lpszClassName = ChildClassName;
return RegisterClassEx(&wcex);
}
static HFONT newFont;
static HWND hChild[9];
unsigned char k[9] = {0};
char text[] = {' ', 'X', '0'};
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
static int sx, sy;
switch (message)
{
case WM_CREATE:
MyRegisterChildClass();
for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
break;
case WM_SIZE:
if(wParam == SIZE_MINIMIZED)
break;
sx = LOWORD(lParam)/3;
sy = HIWORD(lParam)/3;
if(newFont)
DeleteObject(newFont);
newFont = CreateFont(min(sx, sy), 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
for(i = 0; i < 9; i++)
{
MoveWindow(hChild[i], (i%3)*sx, (i/3)*sy, sx, sy, TRUE);
UpdateWindow(hChild[i]);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_NEW:
for(i = 0; i < 9; i++)
{
k[i] = 0;
InvalidateRect(hChild[i], NULL, TRUE);
UpdateWindow(hChild[i]);
}
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
int s, i;
char *ch;
switch(message)
{
case WM_LBUTTONDOWN:
for(i = 0; hWnd != hChild[i]; i++)
;
if(k[i])
break;
else
k[i] = 1;
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
srand(lParam);
for(i = s = 0; i < 9; i++)
if(k[i])
s++;
if(s == 9)
MessageBox(hWnd, L"...",L"...", MB_OK|MB_ICONQUESTION);
else
{
while(true)
{
s = rand()*9/(RAND_MAX+1);
if(k[s])
continue;
k[s] = 2;
InvalidateRect(hChild[s], NULL, TRUE);
UpdateWindow(hChild[s]);
break;
}
}
break;
case WM_PAINT:
for(i = 0; hWnd != hChild[i]; i++);
if(k[i])
{
ch = text+k[i];
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
SelectObject(hDC, newFont);
DrawTextA(hDC, ch, 1, &rt, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
}
else
DefWindowProc(hWnd, message, wParam, lParam);
break;
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I try to create a Tic-Tac-Toe game. Here is the code that I've written by hand (no standard code generated by Visual Studio included). I made 9 child windows. This code runs, but it doesn't show child windows and doesn't react when I push left mouse button. With the help of debugger I saw that messages WM_LBUTTONDOWN and WM_PAINT are never sent to ChildProc function.
What's wrong?

for(i = 0; i < 9; i++)
hChild[i] = CreateWindow(ChildClassName, NULL, WS_CHILD |
WS_DLGFRAME | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL, hInst, NULL);
You are making a traditional mistake, you are blindly hoping that winapi functions will succeed. That's idle hope, CreateWindow() fails and returns NULL. Something you could also see with the debugger, you'll see the hChild array contain nothing but nulls. Always write defensive code, at the absolute minimum use assert() to backup your assumptions:
for(i = 0; i < 9; i++) {
hChild[i] = CreateWindow(ChildClassName, ...);
assert(hChild[i]);
}
Lots of other places in your code where you should do this. You'll now have to trouble diagnosing failure.
The actual bug is located in ChildProc():
default:
DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
Or in other words, it always return 0. That's not okay, you should only return that value when you processed the message. You didn't process every message. Again use the debugger and set a breakpoint on the switch() statement in ChildProc. You'll see the first message being improperly handled, WM_NCCREATE. Which requires you to return TRUE to continue creation of the window. You don't, you return FALSE. So that's a quick end to the window getting created. You must return the value of DefWindowProc(). Fix:
default:
return DefWindowProc(hWnd, message, wParam, lParam);

Related

Can't display unicode on title bar in WIN32

I have been trying to create a Window whose title bar could be in any language. But I am getting something like ▯*. I writing as escape characters as of now. I am attesting the entirity of the code.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
switch(Message) {
case WM_KEYDOWN: {
switch(WParam) {
case 'O': {
DestroyWindow(Window);
} break;
}
} break;
case WM_DESTROY: {
PostQuitMessage(0);
} break;
default: {
return DefWindowProc(Window, Message, WParam, LParam);
}
}
return 0;
}
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, PSTR CmdLine, int CmdShow) {
WNDCLASSW WindowClass = {0};
const wchar_t* ClassName = L"MyWindowClass";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = ClassName;
WindowClass.hCursor = LoadCursor(NULL, IDC_CROSS);
MessageBoxW(0, L"\u0906\u092a", L"\u0906\u092a", 0);
if(!RegisterClassW(&WindowClass)) {
MessageBoxW(0, L"RegisterClass failed", 0, 0);
return GetLastError();
}
HWND Window = CreateWindowExW(0, ClassName, L"\u0906\u092a",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, Instance, 0);
if(!Window) {
MessageBoxW(0, L"CreateWindowEx failed", 0, 0);
return GetLastError();
}
int Running = 1;
while(Running) {
MSG Message;
while(GetMessageW(&Message, NULL, 0, 0)) {
if(Message.message == WM_QUIT) Running = 0;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
}
return 0;
}
I was expecting the title bar to be something like 'आप'

Window theme changes unintentionally

When I first run the program, the window's theme is Windows 11 (as intended):
However, after a few frame updates, the theme changes to a previous version of Windows, and the title text also disappears:
This is my Framework class:
#include "Framework.h"
LRESULT CALLBACK Framework::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Framework* pThis = nullptr;
if (msg == WM_CREATE)
{
CREATESTRUCT* pcs = reinterpret_cast<CREATESTRUCT*>(lParam);
pThis = reinterpret_cast<Framework*>(pcs->lpCreateParams);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
}
else
{
pThis = reinterpret_cast<Framework*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
if (pThis)
return pThis->OnProcessMessage(hwnd, msg, wParam, lParam);
else
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT Framework::OnProcessMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if(mRenderer)
return mRenderer->OnProcessMessage(hwnd, msg, wParam, lParam);
return NULL;
}
void Framework::Run()
{
RECT r;
GetClientRect(mWinHandle, &r);
mWidth = r.right - r.left;
mHeight = r.bottom - r.top;
std::atexit(ReportLiveObjects);
ShowWindow(mWinHandle, SW_SHOWNORMAL);
mRenderer = make_shared<DX12Renderer>();
mRenderer->Init(mWinHandle, mWidth, mHeight);
mRenderer->BuildObjects();
MsgLoop();
DestroyWindow(mWinHandle);
}
void Framework::Init(const string& winTitle, uint32_t width, uint32_t height)
{
const WCHAR* className = L"Main Window";
// Register the window class
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = className;
wc.hIconSm = LoadIcon(wc.hInstance, IDI_APPLICATION);
if (RegisterClassEx(&wc) == 0)
{
return;
}
// Window size we have is for client area, calculate actual window size
RECT r{ 0, 0, (LONG)width, (LONG)height };
int windowWidth = r.right - r.left;
int windowHeight = r.bottom - r.top;
// create the window
wstring wTitle = stringTowstring(winTitle);
mWinHandle = CreateWindow(className, wTitle.c_str(),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
windowWidth, windowHeight, NULL, NULL,
GetModuleHandle(NULL), this);
if (mWinHandle == nullptr)
{
return;
}
}
void Framework::MsgLoop()
{
MSG msg{};
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
mRenderer->Update();
mRenderer->Draw();
}
}
}
And this is my WinMain() function:
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int mCmdShow)
{
#if defined(DEBUG) || defined(_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
try
{
Framework app;
app.Init("Chulsu Renderer");
app.Run();
}
catch (std::exception& ex)
{
MessageBoxA(nullptr, ex.what(), "ERROR", MB_OK);
return -1;
}
return 0;
}
Lastly, message input processing functions:
LRESULT DX12Renderer::OnProcessMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_ACTIVATE:
break;
case WM_SIZE:
mSwapChainSize.x = LOWORD(lParam);
mSwapChainSize.y = HIWORD(lParam);
if (wParam == SIZE_MAXIMIZED)
{
OnResize();
}
else if (wParam == SIZE_RESTORED)
{
if (mDevice) {
OnResize();
}
}
break;
case WM_ENTERSIZEMOVE:
break;
case WM_EXITSIZEMOVE:
OnResize();
break;
case WM_GETMINMAXINFO:
reinterpret_cast<MINMAXINFO*>(lParam)->ptMinTrackSize = { 200, 200 };
break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
OnProcessMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
OnProcessMouseUp(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case WM_MOUSEMOVE:
OnProcessMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
case WM_KEYDOWN:
case WM_KEYUP:
if (wParam == VK_ESCAPE)
{
PostQuitMessage(0);
return 0;
}
OnProcessKeyInput(msg, wParam, lParam);
break;
case WM_MENUCHAR:
return MAKELRESULT(0, MNC_CLOSE);
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
void DX12Renderer::OnResize()
{
}
void DX12Renderer::OnProcessMouseDown(WPARAM buttonState, int x, int y)
{
}
void DX12Renderer::OnProcessMouseUp(WPARAM buttonState, int x, int y)
{
}
void DX12Renderer::OnProcessMouseMove(WPARAM buttonState, int x, int y)
{
}
void DX12Renderer::OnProcessKeyInput(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
}
void DX12Renderer::Update()
{
}
If you need full codes, here's a GitHub page:
https://github.com/kcjsend2/Chulsu
It's a DirectX12 + Win32 application, but I think the DirectX12 layer probably has nothing to do with this problem.
UPDATE:
Seriously, this problem is really odd.
When I replace Framework::OnProcessMessage() like this:
LRESULT Framework::OnProcessMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_KEYDOWN:
case WM_KEYUP:
if (wParam == VK_ESCAPE) {
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Then it works well.
But no matter what's in the function, if I return mRenderer->OnProcessMessage(), it just makes the bug above.
LRESULT Framework::OnProcessMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (mRenderer)
return mRenderer->OnProcessMessage(hwnd, msg, wParam, lParam);
return DefWindowProc(hwnd, msg, wParam, lParam);
}
problem was because of OnProcessMessage returns few NULLs when Renderer is not initialized.
change it to return DefWindowProc, it fixed problem.

How does a single wndproc let each window know its serial number?

int Num = 0;
LRESULT CALLBACK TestWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
RECT rc;
GetClientRect(hWnd, &rc);
RECT Winrc;
GetWindowRect(hWnd, &Winrc);
SYSTEMTIME time;
GetLocalTime(&time);
static const wchar_t* BoxTxt = L"";
static int MeIs = Num;
switch (message)
{
case WM_CREATE:
{
SetWindowLong(hWnd, GWL_EXSTYLE,
GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 220, LWA_ALPHA);
//GhWnd = hWnd;
break;
}
case WM_LBUTTONUP:
{
wchar_t meChar[20] = L"";
_itow(MeIs, meChar, 10);
MessageBox(0, meChar, meChar, 0);
}
case WM_SIZE:
{
InvalidateRect(hWnd, &rc, 1);
break;
}
case WM_NCLBUTTONDBLCLK:
{
break;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_CLOSE:
{
Num -= 1;
DestroyWindow(hWnd);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int CreateTestWindow()
{
//Call testwndproc. To reduce the length of the problem description, omit these codes
Num+=1;
return 0;
}
In the above code, when I create multiple windows and click it, it should pop up "1", "2", "3"... But actually all pop up "1".
static int MeIs = 0;
case WM_CREATE:
{
MeIs = Num;
}
Change to the above code and the serial number of the last window will pop up. For example, when the fourth window is created, all windows will pop up "4"
In practical application, each window has its own settings and is stored in the vector. Each window finds its own settings according to its own serial number:
struct Data
{
int x;
int y;
int width;
int height;
const wchar_t* text;
}
std::vector<data>UserData(32);//Max:32
//then read them from file,But the window must know which window it is:UserData[i].
For example,the first window will set their coordinates to UserData[1].x and UserData[1].y,also need to save the file when closing.
Any idea?thank you!
There are a couple of ways to maintain per-window data using the Win32 API.
The simplest is using the GWL_USERDATA slot accessible via GetWindowLongPtr(...) and SetWindowLongPtr(...). A typical way to initialize this user data value is to use the creation parameters passed to the WM_CREATE message by the CreateWindow call.
Code below:
#include <windows.h>
#include <string>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct SomeData {
int n;
std::wstring str;
};
int RegisterWindow(HINSTANCE hInstance, const wchar_t* wnd_class) {
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(WHITE_BRUSH);
wc.lpszClassName = wnd_class;
if (!RegisterClass(&wc)) {
return 1;
}
return 0;
}
int CreateWindowWithUserData(HINSTANCE hInstance, const wchar_t* wnd_class, int n, const std::wstring& str) {
auto* data_ptr = new SomeData{ n, str };
if (!CreateWindow(wnd_class, L"Window text", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, data_ptr))
return 2;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const auto* wnd_class = L"foobar";
RegisterWindow(hInstance, wnd_class);
for (int i = 1; i <= 5; i++) {
CreateWindowWithUserData(hInstance, wnd_class, i, L"blah");
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE: {
CREATESTRUCT* create_struct = reinterpret_cast<CREATESTRUCT*>(lParam);
SomeData* user_data = reinterpret_cast<SomeData*>(create_struct->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG>(user_data));
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_PAINT: {
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT r = { 20, 20, 300, 35 };
auto msg = user_data->str + L" " + std::to_wstring(user_data->n);
DrawText(hdc, msg.c_str(), -1, &r, DT_SINGLELINE);
EndPaint(hWnd, &ps);
}
return 0;
case WM_DESTROY: {
SomeData* user_data = reinterpret_cast<SomeData*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
delete user_data;
}
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Another way to do something similar is to use the cbWndExtra extra field when registering the window class, as discussed in this answer.
You can:
Indeed store data in Window. SetProp, SetWindowLong+GWL_USERDATA, SetWindowLong+cbWndExtra
Map HWND to your data, like using c++ std::map
Use a thunk to have an associated object, like ATL, see ATL thunk header for available APIs (have to do it manually for older OSes)

Win32 SendInput mousemove lag and freeze

I am trying to move the mouse (on Windows 10) using SendInput when I perform a physical mouse click. It works fine if I click once or twice, but if clicking for examples 6 times in quick succession the mouse lags for a few seconds then the program stops responding.
Is there any obvious reason why this is happening?
(Edited)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
LRESULT CALLBACK MouseHook(int, WPARAM, LPARAM);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
{
HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseHook, NULL, 0);
MessageBox(NULL, L"Hello", L"Hello", MB_OK);
UnhookWindowsHookEx(hook);
return 0;
}
LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
switch (wParam) {
case WM_RBUTTONUP:
INPUT buffer;
ZeroMemory(&buffer, sizeof(buffer));
buffer.type = INPUT_MOUSE;
buffer.mi.dx = 0;
buffer.mi.dy = 10;
buffer.mi.mouseData = 0;
buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
buffer.mi.time = 0;
buffer.mi.dwExtraInfo = 0;
SendInput(1, &buffer, sizeof(INPUT));
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Using Raw Input sample:
#include <windows.h>
#include <iostream>
using namespace std;
BOOL registerTouchpadForInput(HWND hWnd)
{
RAWINPUTDEVICE rid;
rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
rid.usUsagePage = 1;
rid.usUsage = 2;
rid.hwndTarget = hWnd;
return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
void getinputdata(LPARAM lparam)
{
HRAWINPUT hInput = (HRAWINPUT)lparam;
RAWINPUT input = { 0 };
UINT size = sizeof(RAWINPUT);
GetRawInputData(hInput, RID_INPUT,&input, &size,sizeof(RAWINPUTHEADER));
if (RIM_TYPEMOUSE == input.header.dwType)
{
if (input.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
{
INPUT buffer;
ZeroMemory(&buffer, sizeof(buffer));
buffer.type = INPUT_MOUSE;
buffer.mi.dx = 0;
buffer.mi.dy = 10;
buffer.mi.mouseData = 0;
buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
buffer.mi.time = 0;
buffer.mi.dwExtraInfo = 0;
SendInput(1, &buffer, sizeof(INPUT));
}
}
return;
}
static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL registrationStatus = false;
switch (message)
{
case WM_CREATE:
registrationStatus = registerTouchpadForInput(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_INPUT:
getinputdata(lParam);
return DefWindowProc(hwnd, message, wParam, lParam);
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int main()
{
WNDCLASSEX wndclass = {
sizeof(WNDCLASSEX),
CS_DBLCLKS,
NVTouch_WindowProc,
0,
0,
GetModuleHandle(0),
LoadIcon(0,IDI_APPLICATION),
LoadCursor(0,IDC_ARROW),
HBRUSH(COLOR_WINDOW + 1),
0,
L"myclass",
LoadIcon(0,IDI_APPLICATION)
};
bool isClassRegistered = false;
isClassRegistered = RegisterClassEx(&wndclass);
if (isClassRegistered)
{
HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
if (window)
{
ShowWindow(window, SW_SHOWDEFAULT);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}

Weird behaviour when global variables are added in another file

Here's my simple program:
#include "stdafx.h"
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
The output is as expected.
I moved
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
into Global.h and I added #include "Global.h" in my main file.
Main File :
#include "stdafx.h"
#include<Windows.h>
#include "Global.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
Global.h
#pragma once
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
I get a erroneous white window.
I don't understand why this is happening because the compiler will anyway copy the contents of Global.h in to main file, so both variants should produce same results.
What is the cause of this problem ?
There is a bug here:
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void foo()
{
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
}
This should be should be i < 512. Otherwise it overwrites a random memory location, this can result in an error in a different location, or no error if you are lucky. Debugger may report a nonsensical error, or no error at all. If screenBuffer was created on stack, debugger may give "heap corruption" error.
Consider using std::vector to avoid this problem in future.
vector<int> vec;
vec[vec.size()] = 0;//<- debug error
Side note: SetDIBitsToDevice or StretchDIBits will set bits directly:
void draw(HWND hwnd)
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biWidth = WIDTH;
bi.bmiHeader.biHeight = HEIGHT;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(hwnd);
SetDIBitsToDevice(hdc, 0, 0, WIDTH, HEIGHT, 0, 0, 0, HEIGHT, screenBuffer,
&bi, DIB_RGB_COLORS);
ReleaseDC(hwnd, hdc);
}