My code is shown below. When the program is running, I click the right mouse button first, then I click the left mouse button. The result is shown as in the first picture. According to the help document of ScrollWindow function, if the fourth parameter is NULL, the entire client area should be scrolled. Why is there a 10 pixels gap at x = 30 device units?
I'm wondering why the result is not shown like the second picture.
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
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) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
SetRect(&rect, 30, 0, 70, 100);
ScrollWindow(hwnd, 10, 0, NULL, &rect);
UpdateWindow(hwnd);
ReleaseDC(hwnd, hdc);
return 0;
case WM_RBUTTONDOWN:
hdc = GetDC(hwnd);
Ellipse(hdc, 0, 0, 100, 100);
ReleaseDC(hwnd, hdc);
return 0;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
if the fourth parameter is NULL, the entire client area should be scrolled.
You also specify a clipping rectangle (the 5th parameter), so of course not the entire client area will be scrolled. But actually that's not relevant for the problem.
Why is there a 10 pixels gap at x = 30 device units?
Because you don't paint that gap when Windows tells you to do so.
From MSDN:
The area uncovered by ScrollWindow is not repainted, but it is combined into the window's update region. The application eventually receives a WM_PAINT message notifying it that the region must be repainted.
Your WM_PAINT handler does ... nothing except lying to Windows by validating the update region.
Fix your code by doing all the painting only in WM_PAINT. When you scroll in WM_LBUTTONDOWN you will also have to increment a variable that stores the scroll position. Add the scroll position to the coordinates you pass to Ellipse() in WM_PAINT. Now you should get a result like the 2nd picture.
I suggest to find a good tutorial on Win32 painting in general as some basic knowledge seems to be missing here. Get an understanding about what the "update region" is and how it interacts with the paint cycle.
Related
I try to set my preferred device context properties in WM_CREATE message and then use it in WM_PAINT message. My method is to use SaveDC and RestoreDC function in WM_CREATE and WM_PAINT message respectively. But the result doesn't meet my need. What I really need is to show a circle in the center of the client area.
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
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) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect;
static int nSavedDC;
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SetMapMode(hdc, MM_LOMETRIC);
GetClientRect(hwnd, &rect);
SetViewportOrgEx(hdc, rect.right/2, rect.bottom/2, NULL);
nSavedDC = SaveDC(hdc); //I want to save the current state of device context to be used in WM_PAINT message.
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
RestoreDC(hdc, nSavedDC); //Restore the the state of device context which is saved in WM_CREATE message.
Ellipse(hdc, -100, 100, 100, -100);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
Your code lacks error handling. You need to inspect all the values returned by each GDI function call.
As described on MSDN page the purpose of SaveDC / RestoreDC is mostly to restore state to original after you finish drawing. And this is exactly what you aren't doing in both WM_CREATE and WM_PAINT message handlers. You always leave DC in modified state.
As for using SaveDC / RestoreDC to set up DC state once and then quickly restore it at every paint operation instead of setting up from scratch every time I think of at least one obstacle: If some other function calls RestoreDC in between handlers DC restoring item that wasn't on top of the DC states stack then your saved state that was on top of the stack will get destroyed as described here.
I am replacing BeginPaint-EndPaint in a simple window with GetDC-ReleaseDC.
I am reading Charles Petzold Programming Windows 5th Edition.
Here is my code with the changes and the lines changed as comments:
#include<Windows.h>
#include<mmsystem.h>
LRESULT CALLBACK myWndProc(HWND windowHandle, UINT winMessage, WPARAM wParam, LPARAM lParam);
int
WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX myWndClass;
MSG msg;
HWND myWndHandle;
wchar_t szmyWndClassName[] = TEXT("SotoWindClass");
wchar_t szmyWndowName[] = TEXT("SotoWindow");
myWndClass.cbClsExtra = 0;
myWndClass.cbSize = sizeof(WNDCLASSEX);
myWndClass.cbWndExtra = 0;
myWndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
myWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
myWndClass.hIcon = LoadIcon(NULL, IDI_HAND);
myWndClass.hIconSm = NULL;
myWndClass.hInstance = hInstance;
myWndClass.lpfnWndProc = myWndProc;
myWndClass.lpszClassName = szmyWndClassName;
myWndClass.lpszMenuName = NULL;
myWndClass.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&myWndClass))
{
MessageBoxEx(NULL, TEXT("I need at least WINNT"), szmyWndClassName, MB_ICONERROR, 0);
}
myWndHandle = CreateWindowEx(
WS_EX_LEFT,
szmyWndClassName,
szmyWndowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(myWndHandle, iCmdShow);
UpdateWindow(myWndHandle);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK myWndProc(HWND windowHandle, UINT winMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
//PAINTSTRUCT ps;
RECT rc;
wchar_t displayText[] = TEXT("Display My Text!!!!");
switch (winMessage)
{
case WM_CREATE:
{
PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
}break;
case WM_PAINT:
{
/*
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(WindowHandle, &ps);
return(0);
*/
hdc = GetDC(windowHandle);
GetClientRect(windowHandle, &rc);
//ValidateRect(windowHandle, &rc);
DrawText(hdc, displayText, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
ReleaseDC(windowHandle, hdc);
return(0);
}
case WM_DESTROY:
{
PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC);
PostQuitMessage(0);
return(0);
}
}
return(DefWindowProc(windowHandle, winMessage, wParam, lParam));
}
My question is:
Why DrawText is still displaying the message when i haven't called ValidateRect?
From what i understand(which is obviously incorrect) the text inside RECT rc shouldn't appear, unless I call ValidateRect.
When the window is displayed the text drawn is flickering which i assume happens because Windows are calling WM_PAINT and are trying to validate rc (my client area) but DrawText still manages to display the text line every time.
I am a bit confused.
Your text is rendered again and again, because you haven't called ValidateRect. EndPaint calls ValidateRect to mark the area rendered during this paint cycle as valid, i.e. doesn't need rendering.
Leaving an area marked as invalid doesn't stop you drawing to it, it just means the system won't think you have drawn to it and will keep asking you to.
(posted as community wiki, since the question was answered in the comments)
I am experimenting on Windows 7 64 bit OS with win32 API.When i run my Program on debug mode my window appears but i have 2 bugs. Firt things first here is my api code modified from Charles Petzold book Ch3:
#include<Windows.h>
#include<mmsystem.h>
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviousInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX MyWindowsClass;
static wchar_t szMyWindowsClassName[] = TEXT("The Name of My Window Class");
static wchar_t szAppName[] = TEXT("AppName");
HWND myWindowHandle;
MSG msg;
MyWindowsClass.hInstance = hInstance;
MyWindowsClass.style = CS_HREDRAW | CS_VREDRAW;
MyWindowsClass.lpfnWndProc = HandleMyWindowsClassMessages;
MyWindowsClass.lpszClassName = szMyWindowsClassName;
MyWindowsClass.cbSize = sizeof(WNDCLASSEX);
MyWindowsClass.cbClsExtra = 0;
MyWindowsClass.cbWndExtra = 0;
MyWindowsClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
MyWindowsClass.hCursor = LoadCursor(NULL, IDC_ARROW);
MyWindowsClass.hIcon = LoadIcon(NULL, IDI_SHIELD);
MyWindowsClass.hIconSm = NULL;
MyWindowsClass.lpszMenuName = NULL;
if (!RegisterClassEx(&MyWindowsClass))
{
MessageBoxEx(0, TEXT("This Programm Requires WINNT!"), szMyWindowsClassName, MB_ICONERROR, 0);
return(0);
}
myWindowHandle = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
szMyWindowsClassName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(myWindowHandle, iCmdShow);
UpdateWindow(myWindowHandle);
while (GetMessage(&msg, myWindowHandle, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
{
//wchar_t szGreeting[] = TEXT("Heeeey");
HDC hdc;
PAINTSTRUCT ps;
switch (Message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
} break;
case WM_PAINT:
{
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &ps.rcPaint, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//TextOut(hdc, 0, 0, szGreeting, (int)wcslen(szGreeting));
EndPaint(WindowHandle, &ps);
return(0);
}break;
case WM_DESTROY:
{
PostQuitMessage(0);
return(0);
}break;
}
return(DefWindowProc(WindowHandle, Message, wParam, lParam));
}
Bug1:PlaySound keeps playing the wav even when i have closed-destroyed the Window.When I used the original example with plain WNDCLASS the bug dissapeared!
So I must be doing something wrong using WNDCLASSEX ???.
Also in this bug to end execution of debbuging I have to press Shift+F5.
Bug2:TextOut vs DrawText
Info:I have only 1 screen.I program on my laptop.
When I use drawText and the text in my window goes out of my desktop screen borders the text just doesnt update correclty.
When I use TextOut the bug dissapears!!!
Why???
Below i have some pitures ordered to explain this.
The Program starts in debug mode
Moving the window out of Desktop borders(including the displayed text)
Moving the window back inside my desktop area(the text has been mutated)
Window is destroyed and sound will keep playing even when the wav ends.
Any help in any of the 2 bugs would be greatly appreciated.
2nd version of my WndProc:
LRESULT CALLBACK HandleMyWindowsClassMessages(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
{
//wchar_t szGreeting[] = TEXT("Heeeey");
HDC hdc;
PAINTSTRUCT ps;
RECT rc;
rc.left = 50; rc.top = 100; rc.right = 200; rc.bottom = 200;
switch (Message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return(0);
} break;
case WM_PAINT:
{
hdc = BeginPaint(WindowHandle, &ps);
DrawText(hdc, TEXT("Hello Win 7!!!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//TextOut(hdc, 0, 0, szGreeting, (int)wcslen(szGreeting));
EndPaint(WindowHandle, &ps);
return(0);
}break;
case WM_DESTROY:
{
PlaySound(NULL, NULL, SND_FILENAME | SND_ASYNC);
PostQuitMessage(0);
return(0);
}break;
}
return(DefWindowProc(WindowHandle, Message, wParam, lParam));
}
Call PlaySound( NULL, NULL, SND_FILENAME | SND_ASYNC) before PostQuitMessage to stop the sound.
About DrawText - note that BeginPaint returns rectangle rcPaint for the region which needs redraw. If you are using it for start point of DrawText, the text will appear at different places. For example - when first created, the region will start at 0,0. Then you can move another window over DrawText application window and it can require repaint from point 80,100 to lower right corner. Try with absolute (client) coordinates, e.g. define RECT rc and set rc.left = 50; rc.top = 100; rc.right = 200; rc.bottom = 200; (always the same position).
I am trying to learn win32 API using Programming Windows fifth Edition.
As I was experimenting with some Identifiers I noticed something that I am not able to understand why is happening.I` ll be more specific, here is my code:
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int
WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("HELLOWIN");
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_SHIELD);
wndclass.hCursor = LoadCursor(NULL, IDC_CROSS);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(0, TEXT("This Programm Requires WINNT!"), szAppName, MB_ICONERROR);
return(0);
}
hwnd = CreateWindow(szAppName, //window class name
TEXT("The Hello Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle(we have top-level window)
NULL, //window menu handle
hInstance, //programm instances handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
{
PlaySound(TEXT("D:\\mp3\\aywy._&_EphRem_-_Adderall.wav"), NULL, SND_FILENAME | SND_ASYNC);
return 0;
} break;
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
} break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
With this code everything works great and as expected but...
when i change:
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
to
wndclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
the cursor icon is lost on the background and is only visisble in the small line
in which i use drawText().What confuses me is that this doesnt happen when my background is white(WHITE_BRUSH).
Could someone explain why?
PS:If this behaviour is explained later in the book (I am finishing chapter 3 currently) just type Read more so i don`t waste you time.
Thank you in advance.
What is probably happening is that the 'cross' cursor that you are using is a very thin cursor implemented (either by windows or by the hardware) by NEGating the underlying pixels instead of painting above them. This works fine for all colors except the 0x808080 gray, because negating 0x808080 still gives 0x808080, so the cursor is invisible. Try using light gray, dark gray, or another cursor which is not so thin.
As MSDN describes:
When the mouse moves over a window, the window receives a WM_SETCURSOR message (unless another window has captured the mouse).
If the application passes WM_SETCURSOR to DefWindowProc, the DefWindowProc function uses the following algorithm to set the cursor image:
If the window has a parent, forward the WM_SETCURSOR message to the parent to handle.
Otherwise, if the window has a class cursor, set the cursor to the class cursor.
If there is no class cursor, set the cursor to the arrow cursor.
And here's my source code:
#include <tchar.h>
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInsTance, LPTSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
HWND hWnd;
BOOL ret;
MSG msg;
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = TEXT("MainWindow");
wcex.hIconSm = wcex.hIcon;
RegisterClassEx(&wcex);
hWnd = CreateWindow(wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (ret = GetMessage(&msg, NULL, 0, 0))
{
if (ret == -1)
{
return EXIT_FAILURE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
When I move my cursor quickly over the window, the cursor doesn't change to an arrow, it become a resize arrow; if I set wcex.hCursor to LoadCursor(NULL, IDC_ARROW), everything will be all right. My question is: why doesn't my code work as MSDN says?
I mean, if I don't set wcex.hCursor, and I don't handle the WM_SETCURSOR message, the DefWindowProc should "set the cursor to the arrow cursor", but it seems it doesn't. Why is that?
See description of the hCursor member of the WNDCLASSEX:
A handle to the class cursor. This member must be a handle to a cursor
resource. If this member is NULL, an application must explicitly set
the cursor shape whenever the mouse moves into the application's
window.
WNDCLASSEX structure