WINapi. Can't erase background of window with ellipse - c++

I'm just trying to draw an ellipse:
case WM_PAINT:
hdc = BeginPaint(parentWindow, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(parentWindow, &ps);
, and then erase it with drawing a new ellipse with some new parameters every second using timer:
case WM_CREATE:
SetTimer(hWnd, 1, 1000, NULL);
break;
case WM_TIMER:
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
break;
But ellipses are not erased and layered:
However, i tried to trace WM_ERASEBKGND and it really is sent every InvalidateRect.
Full code:
#include <Windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <iostream>
TCHAR szWindowClass[] = TEXT("CreateThreadWindow");
TCHAR szAppName[] = TEXT("CreateThreadExample");
BOOL InitWindow(HINSTANCE, int);
ATOM MyRegisterClass(HINSTANCE);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND parentWindow;
MSG msg;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MyRegisterClass(hInstance);
if (!InitWindow(hInstance, nCmdShow))
return FALSE;
BOOL bRet;
while ((bRet = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0)
{
if (bRet == -1)
return FALSE;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wndClass;
memset(&wndClass, 0, sizeof(wndClass));
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hInstance;
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szWindowClass;
return RegisterClass(&wndClass);
}
BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{
parentWindow = CreateWindow(szWindowClass, szAppName, WS_OVERLAPPEDWINDOW,
300, 0, 600, 600, NULL, NULL, hInstance, NULL);
ShowWindow(parentWindow, nCmdShow);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
static int x = 0, y = 0, width = 200, height = 100;
switch (message) {
case WM_ERASEBKGND:
_RPT1(0, "%s\n", "erase");
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
break;
case WM_CREATE:
SetTimer(hWnd, 1, 1000, NULL);
break;
case WM_TIMER:
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wparam, lparam);
}
}

Your code isn't erasing anything. It's just drawing an ellipse at the specified coordinates. The previously-drawn ellipse is still there.
You mention the WM_ERASEBKGND message, but there are two reasons why that isn't working for you:
In your window procedure (WndProc), you handle the WM_ERASEBKGND message explicitly, which means that it doesn't get passed to the default window procedure (DefWindowProc). A better way to write your window procedure would be the following:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static int x = 0, y = 0, width = 200, height = 100;
switch (message) {
case WM_ERASEBKGND:
{
_RPT1(0, "%s\n", "erase");
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
return 0;
}
case WM_CREATE:
{
SetTimer(hWnd, 1, 1000, NULL);
break;
}
case WM_TIMER:
{
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
default:
break;
}
return DefWindowProc(hWnd, message, wparam, lparam);
}
Now, the default window procedure gets called every time, unless you explicitly return from inside of a case label.
When you register your window class (inside of MyRegisterClass), you zero all fields of the WNDCLASS structure and then explicitly initialize a couple of them. You don't explicitly initialize the hbrBackground field, so it is being set to 0. And when hbrBackground is 0,
When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function.
This means that the default window procedure isn't doing anything in response to the WM_ERASEBKGND message because you didn't give your window a background brush.
You will either need to set hbrBackground to something like COLOR_WINDOW + 1, or you will need to add code to your WM_ERASEBKGND message handler to erase the window's background yourself.
Or, perhaps an even better option would be to forget about the WM_ERASEBKGND message altogether, as many Windows programmers do, because this two-step erase-and-paint approach tends to cause flicker. Leave the hbrBackground field set to NULL, don't do anything in response to the WM_ERASEBKGND message, and do your erasing at the top of the WM_PAINT handler:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Erase background of entire client area.
RECT rcClient;
GetClientRect(hWnd, &rcClient);
FillRect(hdc, &rcClient, reinterpret_cast<HBRUSH>(COLOR_WINDOW+1));
// Do normal drawing.
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
return 0;
}

Related

Change window's background color with button using winapi

I'm trying to make button change background color of window when clicked. I know that I need to handle this event in WM_COMMAND, where I also check ID of this button, but nothing happens. I tried to debug and my program recognizes ID correctly. The piece of code used for changing color works well when in main loop but it doesn't do anything when in WM_COMMAND. How do I solve this problem? Whole code:
#include <Windows.h>
#define BUTTON_ID 100
struct status_info {
const char* waiting = "Waiting for connection...";
const char* connected = "Connected.\nWaiting for frajer to copy number.";
const char* changed = "Number changed.";
}status_info;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
const wchar_t CLASS_NAME[] = L"Name";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = (LPCSTR)CLASS_NAME;
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
RegisterClass(&wc);
//main window
HWND hwnd = CreateWindowEx(0, (LPCSTR)CLASS_NAME, (LPCSTR)"Hacker", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, NULL, NULL, hInstance, NULL);
//number window
HWND number = CreateWindowEx(WS_EX_WINDOWEDGE, TEXT("Static"), TEXT("Account number:\n00 1234 1234 1234 1234 1234 1234"), WS_CHILD | WS_VISIBLE, 5, 5, 240, 40, hwnd, NULL, NULL, NULL);
//status window
const char* status_message = status_info.waiting;
HWND status = CreateWindowEx(WS_EX_WINDOWEDGE, TEXT("Static"), TEXT(status_message), WS_CHILD | WS_VISIBLE, 5, 55, 240, 40, hwnd, NULL, NULL, NULL);
//button
HWND button = CreateWindowEx(0, "BUTTON", "Nightmode", WS_CHILD | WS_VISIBLE, 100, 100, 150, 30, hwnd, (HMENU)BUTTON_ID, hInstance, NULL);
MSG msg;
WNDCLASS okno;
while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
SetWindowText(status, status_message);
}
return msg.wParam;
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//MessageBox(hwnd, L"1", L"1", 0);
return (0);
case WM_DESTROY:
//MessageBox(hwnd, L"2", L"2", 0);
PostQuitMessage(0);
return (0);
case WM_COMMAND: {
if (LOWORD(wParam) == BUTTON_ID) {
PAINTSTRUCT ps;
RECT rc;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetBkColor(hdc, BLACK_BRUSH);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, 0, 0, 0);
EndPaint(hwnd, &ps);
}
break;
}
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
BeginPaint/EndPaint should be used in response to WM_PAINT only.
You can use GetDC(hwnd)/ReleaseDC(hwnd, hdc) to obtain hdc for painting on device context outside of WM_PAINT, but this will be temporary. The next refresh message causes the window to be erased and repainted according to what's in WM_PAINT
SetDCBrushColor can be used if the goal is to avoid creating brush handle.
static COLORREF bkcolor = RGB(255,255,255);
switch(message)
{
case WM_COMMAND:
if(LOWORD(wparam) == BUTTON_ID)
{
bkcolor = RGB(255, 0, 0);
InvalidateRect(hwnd, NULL, TRUE);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetDCBrushColor(hdc, bkcolor);
FillRect(hdc, &rc, (HBRUSH)GetStockObject(DC_BRUSH));
//or use ps.rcPaint to repaint only the section which requires update
//FillRect(hdc, &ps.rcPaint, (HBRUSH)GetStockObject(DC_BRUSH));
EndPaint(hwnd, &ps);
return 0;
}
case WM_ERASEBKGND:
//return 0 means WM_PAINT handles the background
return 0;
Alternatively, use SetClassLongPtr to replace the background brush:
static HBRUSH bkbrush = NULL;
switch(message)
{
case WM_COMMAND:
if(LOWORD(wparam) == BUTTON_ID)
{
COLORREF bkcolor = RGB(rand() % 256, rand() % 256, rand() % 256);
if(bkbrush)
DeleteObject(bkbrush);
bkbrush = CreateSolidBrush(bkcolor);
SetClassLongPtr(hwnd, GCL_HBRBACKGROUND, (LONG)bkbrush);
InvalidateRect(hwnd, NULL, TRUE);
}
break;

Importing a BitMap makes my Window Lagg

I need some help here.
Im importing an bitmap onto my Win32 Window. I am building it and after some seconds it's starting to lag a lot. I am not sure why, but I suppose I am not correctly deleting it from memory after using it.
Thank you for Help in advance.
I saw a behavior while I was testing it. If Im not moving the window than it is okey, but after moving it it start to lag and block my IDE. Maybe something with WM_PAINT?
Here is my code.
#include <windows.h>
//For more makros
#include <windowsx.h>
#include "Simulatron.h"
HINSTANCE hProgramInstance;
Simulatron Exo;
char Simulatron::m_szClassName[] = "Simulatron";
Simulatron::Simulatron(HINSTANCE hInstance)
{
m_hInstance = hInstance; // Save Instance handle
m_wndClass.cbSize = sizeof(WNDCLASSEX); // Must always be sizeof(WNDCLASSEX)
m_wndClass.style = CS_DBLCLKS; // Class styles
m_wndClass.lpfnWndProc = MainWndProc; // Pointer to callback procedure
m_wndClass.cbClsExtra = 0; // Extra bytes to allocate following the wndclassex structure
m_wndClass.cbWndExtra = 0; // Extra bytes to allocate following an instance of the structure
m_wndClass.hInstance = hInstance; // Instance of the application
m_wndClass.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDC_MAINCURSOR)); // Class Icon
m_wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Class cursor
m_wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // Background brush
m_wndClass.lpszMenuName = NULL; // Menu Resource
m_wndClass.lpszClassName = (LPCWSTR)m_szClassName; // Name of this class
m_wndClass.hIconSm = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); // Small icon for this class
}
Simulatron::~Simulatron()
{
}
Simulatron::Simulatron()
{
// If we declare a window class with a default constructor,
// we need to reset the window to a nothing
}
LRESULT CALLBACK Simulatron::MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc;
static PAINTSTRUCT ps;
static HDC hdc_mem;
static HBRUSH newbrush;
//Child Window Handles
Simulatron create;
RECT rect;
hProgramInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
static HBITMAP logo = NULL;
static BITMAP bitmap;
logo = (HBITMAP)LoadImage(hProgramInstance, L"Space.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(logo, sizeof(bitmap), &bitmap);
switch (msg)
{
case WM_CREATE:
{
create.Create(hProgramInstance,hwnd,lParam,logo);
}
break;
case WM_GETMINMAXINFO:
{
LPMINMAXINFO pInfo = (LPMINMAXINFO) lParam;
//pInfo -> ptMaxTrackSize.x = 450;
//pInfo -> ptMaxTrackSize.y = 650;
}
break;
case WM_SIZE:
break;
case WM_CTLCOLORSTATIC:
SetTextColor((HDC)wParam, RGB(150, 100, 255));
SetBkMode((HDC)wParam, TRANSPARENT);
newbrush = (HBRUSH)GetStockObject(NULL_BRUSH);
DeleteObject(newbrush);
return (LRESULT)newbrush;
break;
case WM_COMMAND:
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd , &rect);
hdc_mem = CreateCompatibleDC(hdc);
SelectObject(hdc_mem, logo);
BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdc_mem, 0, 0, SRCCOPY);
DeleteObject(hdc_mem);
EndPaint(hwnd, &ps);
break;
//Handle the combinations from the keyboard input
case WM_DESTROY:
PostQuitMessage (0);
DeleteObject(logo);
DeleteBitmap(logo);
break;
default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0;
}
//Create function of all Childs
void Simulatron::Create(HINSTANCE Hinst, HWND hWindow, LPARAM lParam, HBITMAP logo)
{
Hinst = ((LPCREATESTRUCT) lParam) -> hInstance; // handle to instance for custom cursor
logo = (HBITMAP)LoadImage(Hinst, L"Space.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
bool Simulatron::Run(int nCmdShow)
{
if(!RegisterClassEx(&m_wndClass))
return false;
m_hwnd = CreateWindowEx(0,(LPCWSTR)m_szClassName,
L"Simulatron",
//WS_OVERLAPPEDWINDOW,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, // Dissable Resizing and Maximizing
0, 0, 1280, 1000,
NULL, NULL,
m_hInstance,
NULL);
if(!m_hwnd)
return false;
ShowWindow(m_hwnd, nCmdShow);
return true;
}
Simulatron::operator HWND()
{
// This overloaded operator allows us to use HWND anyway we want
return m_hwnd;
}
You load the BMP File over and over again in your MainWndProc. You should load it once at Init and use it from there! Have a look at a win32 API tutorial and you will see that MainWndProc is getting called throughout the whole program lifetime. You could load that image in your WM_CREATE state for example.

Wrong pen color

I try to change pen color with this code :
redPen = CreatePen(PS_SOLID,1,0xFF0000);
SelectObject(hdc, redPen);
but it change from black into blue. And no matter what color is, because pen always will be blue if i try to set new color or black if i do nothing.
Here is whole code:
#include "windows.h"
int N=50;
int M=30;
int X=25;
int width=X * N;
int height=X * M;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE h,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow){
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
wc.cbSize=sizeof(wc);
wc.style=CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc=WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=h;
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor=LoadCursor(h,IDC_ARROW);
wc.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName=NULL;
wc.lpszClassName="main";
wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
if(!RegisterClassEx(&wc)) return 0;
if(!(hwnd=CreateWindowEx(NULL,"main","test",WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,width,height,NULL,NULL,h,NULL))) return 0;
ShowWindow(hwnd,SW_SHOWDEFAULT);
UpdateWindow(hwnd);
while(msg.message != WM_QUIT){
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
HDC hdc;
PAINTSTRUCT ps;
HPEN redPen;
switch (message){
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
redPen = CreatePen(PS_SOLID,1,0xFF0000);
SelectObject(hdc, redPen);
for(int i=0;i<width;i+=X){
MoveToEx(hdc,i,0,NULL);
LineTo(hdc,i,height);
}
for(int j=0;j<height;j+=X){
MoveToEx(hdc,0,j,NULL);
LineTo(hdc,width,j);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
redPen = CreatePen(PS_SOLID,1,0xFF0000);
No, that's definitely the wrong identifier name, it should be "bluePen". COLORREF is encoded as 0x00bbggrr in hex. So 0x00ff0000 is blue, not red.
Fall in the pit of success by using the RGB macro instead:
redPen = CreatePen(PS_SOLID, 1, RGB(0xFF, 0, 0));

Creating a Window in WinAPI after pressing a button

I'm making an auto clicker for a game in WinAPI and I have 4 simple buttons on the main window. When the user presses the 'start' button I want another window to open asking them for settings such as number of times to click and time between clicks. When I try to create a new window, nothing is happening, but everything else works perfectly.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_COMMAND:
{
switch (wParam)
{
case ID_START:
{
HINSTANCE hInstance = GetModuleHandle(CLASS_NAME);
HWND settings = CreateWindowEx(
0,
L"Settings",
L"Settings",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
100, 100, 600, 200,
NULL,
(HMENU) ID_SETTINGS,
hInstance,
NULL
);
MSG msg = { };
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
case ID_QUIT:
{
PostQuitMessage(0);
return 0;
}
case ID_CALIB:
{
if (MessageBox(hwnd, L"You pressed Calibrate", L"Calibrate", MB_OK))
{
return 0;
}
}
case ID_INFO:
{
if (MessageBox(hwnd, L"You pressed about", L"About", MB_OK))
{
return 0;
}
}
}
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
I just started WinAPI today, so I am extremely new. Thanks for any help in advance!
The second parameter to CreateWindowEx must be a class name that you registered earlier by calling RegisterClass.
You are specifying WS_CHILD. But a child must have a parent. Pass the parent HWND into the hwndParent parameter.

Using SS_BITMAP style on static control in a dialog frame

I am attempting to write a slot machine Win32 App that uses images to display the result of the spins. I know how to display an image on a normal LRESULT CALLBACK frame, but i'm lost when it comes to displaying images on a dialog. Could anyone help me by explaining(in-depth) how i would go about displaying images? I really appreciate it.
My current Dialog callback:
BOOL CALLBACK DlgProc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG: //dialog created
g_hbmObject = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_OBJECT));
//initialize slotmachine class
Machine.Initialize(time(0));
if(g_hbmObject == NULL) //test if object is loaded correctly
std::cerr << "Could not load ball..";
break;
case WM_COMMAND: //switch command
switch(LOWORD(wParam))
{
case IDC_SPIN: //slot machine spins
//put spin function, decide what to display
//do i put the display image command here? or where?
break;
case IDC_EXIT: //exit button
DeleteObject(g_hbmObject);
EndDialog(hwnd, 0);
break;
}
break;
case WM_CLOSE:
case WM_DESTROY: //case program is exited
DeleteObject(g_hbmObject);
PostQuitMessage(0);
break;
default:
return FALSE;
}
return TRUE;
}
The following code registers a "REEL" window class: a control that displays a spinning reel for a slot machine. You can create multiple instances of it on a dialog using resource statements like:
CONTROL "",IDC_REEL1,"REEL",0,14,50,40,40
CONTROL "",IDC_REEL2,"REEL",0,70,50,40,40
The reel spins endlessly, but you can easily add private messages to start and stop it.
As explained in the comments, it expects a bitmap representing a reel with resource ID IDB_REEL.
HBITMAP g_hbmpReel;
LRESULT CALLBACK ReelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
const int ReelTimerId = 5;
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, ReelTimerId, 10, 0);
break;
case WM_DESTROY:
KillTimer(hWnd, ReelTimerId);
break;
case WM_SIZE:
SetWindowPos(hWnd, 0, 0, 0, 40, 40, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
break;
case WM_TIMER:
if (wParam == ReelTimerId)
{
int offset = GetWindowLong(hWnd, 0);
offset = (offset + 5) % 120;
SetWindowLong(hWnd, 0, offset);
InvalidateRect(hWnd, 0, FALSE);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC hdcReel = CreateCompatibleDC(hdc);
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcReel, g_hbmpReel);
int offset = GetWindowLong(hWnd, 0);
BitBlt(hdc, 0, 0, 40, 40, hdcReel, 0, offset, SRCCOPY);
SelectObject(hdcReel, hbmpOld);
DeleteDC(hdcReel);
EndPaint(hWnd, &ps);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ATOM RegisterReel(HINSTANCE hInstance)
{
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = ReelWndProc;
// Window data used to hold the position of the reel
wcex.cbWndExtra = sizeof(int);
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = L"REEL";
// IDB_REEL is a 40x160 bitmap representing a reel with THREE 40x40 symbols.
// The bottom 40x40 square should be the same as the topmost.
g_hbmpReel = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_REEL));
return RegisterClassEx(&wcex);
}