How to restrict the mouse cursor inside the window [duplicate] - c++

I'm writing a very simple program to clip the mouse to a specified window. It runs from the system tray without a visible window. Because there will be multiple instances of the same window, it uses EnumWindows() to iterate through every top-level window and compare their hwnd with GetForegroundWindow(). When true, it runs the standard ClipCursor() code. ClipCursor() returns TRUE, and, I've asserted that the RECT set by GetClipCursor() is the exact same as the RECT passed to ClipCursor(). Yet, the cursor is free to move anywhere on the screen.
I've checked that the values in the RECT are the exact values of the window, I've compiled the program in release mode and ran it with admin rights, still nothing. The code below is exactly what runs after we've found the HWND of the GetForegroundWindow():
// Get the window client area.
GetClientRect(hwnd, &rc);
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
ClientToScreen(hwnd, &pt);
ClientToScreen(hwnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
clipped = true;
ClipCursor(&rc);
RECT rect;
GetClipCursor(&rect);
assert(rect.bottom == rc.bottom);
assert(rect.left == rc.left);
assert(rect.right == rc.right);
assert(rect.top == rc.top);
I've removed a lot of the checks because they were getting annoying (I was using MessageBox()'s), but this code is certainly running when it's supposed to. The cursor just isn't getting clipped, and I can't fathom why.

Since the cursor is a shared resource, your attempt to clip it is overwritten by anybody else who calls ClipCursor to unclip the cursor. And a lot of operations automatically unclip the cursor (such as any focus change). It's considered poor form for a background window to change the cursor clip.

Well, it only took me a few days to find out that despite the shared nature of the Cursor resource, if a process is clipping a cursor in certain circumstances that I don't fully know of yet (maybe the process has to be the foreground application? or something like that... I'm not so sure.) then the OS automatically releases the cursor back to full clipping mode (or whatever you'd call it).
Anyway, the fix is to do a low level mouse hook and call the clipcursor from there. Here's some quick proof of concept code (tested and works, although I removed the irrelevant stuff like creating a window or setting up the systray etc):
// Some variables we'll use
bool clipped = false; // Do we need to clip the mouse?
RECT rc; // The clip rect
HHOOK hMouseHook; // Low level mouse hook
// Low level mouse hook callback function
__declspec(dllexport) LRESULT CALLBACK MouseEvent(int nCode, WPARAM wParam, LPARAM lParam)
{
// This part should be rewritten to make it not be a CPU-hog
// But works as a proof of concept
if ( clipped )
ClipCursor(&rc);
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// .... Blah blah blah ....
// Low level mouse hook
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseEvent, hInstance, 0);
// Only included to show that you set the hook before this,
// And unhook after this.
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Unhook the mouse
UnhookWindowsHookEx(hMouseHook);
return msg.wParam;
}

Related

How do I properly move a window with a region?

I've just started looking into window regions, and I'm trying to create an elliptical window that I can move by dragging the client area. Unfortunately, when I drag the window, the window flashes back and forth from the ellipse to the normal window (as if I never called SetWindowRgn), and back, repeatedly and rapidly.
I read on MSDN that I have to call SetWindowRgn(nullptr);, then move the window, then reset the region, which I have already done in my code. I move the window by calling SetWindowPos with SWP_NOZORDER, SWP_NOSIZE, and SWP_NOREDRAW, and I've tried adding on all of SWP_NOSENDCHANGING, SWP_DEFERERASE, and SWP_NOCOPYBITS as well, to no avail.
Here's my window procedure, with emphasis on WM_MOUSEMOVE. I know it won't work if I release the button outside of the window; I was planning to deal with that after this worked. I also left out error checking. It's pretty obvious that the calls do work, though, because the window does move as I drag it.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static bool moving{};
switch (msg) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_LBUTTONDOWN: {
moving = true;
return 0;
}
case WM_LBUTTONUP: {
moving = false;
return 0;
}
case WM_MOUSEMOVE: {
static POINT old{0, 0};
if (moving) {
RECT r;
GetWindowRect(hwnd, &r);
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
RECT newPos;
newPos.left = r.left + x - old.x;
newPos.top = r.top + y - old.y;
SetWindowRgn(hwnd, nullptr, FALSE);
SetWindowPos(hwnd, nullptr, newPos.left, newPos.top, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW
);
SetWindowRgn(hwnd, CreateEllipticRgn(200, 200, 600, 400), FALSE);
}
old.x = GET_X_LPARAM(lParam);
old.y = GET_Y_LPARAM(lParam);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I've also tried calling ValidateRgn(hwnd, nullptr); at the end of WM_MOUSEMOVE, which doesn't change anything. As well, I've tried wrapping the DefWindowProc call in a condition that just returns 0 if moving is set in order to see whether it was just some other message being sent that was messing with it, but that resulted in the window doing nothing when dragged. I then applied that condition to WM_PAINT and WM_ERASEBKGND handlers, but that resulted in the same flickering problem when dragged.
In order to test it more easily, here's full code (just rudimentary window creation etc). Am I going about moving the window the right way? Is there some message or something that I should handle, but don't? This is happening on Window 7 Ultimate N.
A much easier way to handle the move logic is to handle the WM_NCHITTEST message, returning HTCAPTION. This makes Windows handle all the move logic for you.

Resizing Window causes smearing near the right border

I have created a standard win32 windows application in Visual Studio 2010. The only addition I have made is a TextOut call in the WM_PAINT handler that displays the alphabet (repeated 4 times for width) at position 0, 0.
My problem is that when I resize the window, expanding to the right, there is some drawing error by the right side border. Black blocks are shown during the resizing/drawing process as if the right hand edge is being stretched. The result is a strange black “smearing” effect as I resize. It only happens during the resize; once I release the mouse, the window looks correct.
I have tried double buffering to a memory DC, but see the same effect. I am not using any windows themes code.
The only way I can remove the effect is to handle WM_NCPAINT (and return 0) – but, of course, this means the border isn’t painted which won’t be an acceptable solution! I mention it in case it helps anybody with an idea.
Thanks for any ideas or help!
#Arx – Sorry, I hadn’t made myself clear. When I say the borders smear, I meant the right hand edge of the displayed text, not the border itself.
It happens if I just add the TextOut call in the WM_PAINT handler. Handling WM_ERASEBKGRND and setting the window class background brush makes no difference.
#David – Apologies. I see the effect after adding only one line to the standard VS 2008 Win32 application created by the new project wizard – so I didn’t see the point in posting 200+ lines of code with only one line of interest :)
I added this line to the WM_PAINT handler:
TextOut (hdc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ", 104);
Here is the full version of the code with double buffering added. The smearing of the text on the right hand side (by the window edge) as the window is expanded still occurs.
// win32_smearing_at_border.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "win32_smearing_at_border.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
// 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_WIN32_SMEARING_AT_BORDER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER));
// 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_WIN32_SMEARING_AT_BORDER));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = 0; //(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER);
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;
static HDC memory_dc;
static HBITMAP memory_bmp;
static HBITMAP oldbmp;
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_ERASEBKGND:
return 1;
case WM_CREATE:
// Create memory DC
{
HDC dc = GetDC (hWnd);
memory_dc = CreateCompatibleDC (dc);
memory_bmp = CreateCompatibleBitmap (dc, 2560, 1440); // arbitary values for testing, set to my current monitor size.
oldbmp = (HBITMAP)SelectObject(memory_dc, memory_bmp);
TextOut (memory_dc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",104);
ReleaseDC (hWnd, dc);
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, memory_dc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
// Clean up memory DC
SelectObject (memory_dc,oldbmp);
DeleteObject (memory_bmp);
DeleteDC (memory_dc);
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;
}
Hi Arx
Many thanks for trying out the code – I appreciate it. Good to know it’s working for you.
But … I am experiencing some very strange results. I have the “blurring” issue when running on a Windows 7 x64 machine. However, trying it out in a Windows 7 virtual machine (using VMWare on the SAME machine), it works perfectly.
So on the same machine, natively it blurs, but virtually it doesn’t. I even tried a Windows 8 virtual machine, and again it worked fine.
What I have found is that if I select a NON-Aero theme, all works ok (although it’s doesn’t look so good without Aero). And yet on the other machines where it IS working, they DO have Aero themes selected. I really don’t get it.
So that’s not really a solution. I don’t want to have to ask my potential customers to turn Aero off.
I have tried calls to many of the Dwm* functions trying to find a difference between the working and non-working machines but cannot find anything.
If I insert this code:
DWMNCRENDERINGPOLICY policy = DWMNCRP_DISABLED;
DwmSetWindowAttribute(hWnd,
DWMWA_NCRENDERING_POLICY,
(void*)&policy,
sizeof(DWMNCRENDERINGPOLICY));
Just after creating the main window then all works fine again (although, once again, doesn’t look as good without the Aero border).
So am I really at a loss as to how I can move forward. Any ideas gratefully received!
I think I can provide some more insight about where that smearing/blurring is coming from and why you see it more (or differently) in Windows 8/10 Aero.
The fact that your code has:
wcex.style = CS_HREDRAW | CS_VREDRAW;
is the reason why you didn't see the smearing/blurring on Win7. This causes Windows to fill in newly exposed areas of the window that have not yet been drawn by your WM_PAINT with a solid color, which is not perfect but not that distracting.
But under Windows 8/10 Aero, things are different. Apps don't draw directly to the screen, but rather draw to offscreen buffers that are then composited by the evil DWM.exe window manager. It turns out that DWM actually adds another layer of BitBlt-type behavior on top of the existing legacy XP/Vista/7 BitBlt behavior that is affected by CS_HREDRAW | CS_VREDRAW.
And the DWM blit behavior is even more crazy because they don't just copy the client area, but they actually replicate pixels at the edges of your old client area to make the new one.
Unfortunately, making DWM not do its blit is much harder than just passing some extra flags.
I don't have a 100% solution, but please see this Q&A for a sort of timing trick that can be used to greatly reduce the frequency with which DWM messes with your window client area, which will reduce the smearing/blurring:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Enjoy!

How to create menu at the top left corner of a window using openGL

I am writing a game in openGL, in C++ at windows.
I need to add some menus and sub-menus at the top left corner of the window.
I've seen the popup menus on right click but I want the menus to be as any program like firefox, etc.
How can I achieve this?
Edit #1:
I've added a popup menu when a RMB is pressed with these:
glutCreateMenu(MenuSelect);
glutAddMenuEntry("Option1Name", option1);
glutAddMenuEntry("Option2Name", option2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
and into the MenuSelect function I am printing some text.
You have at least two choices:
use some Windows API (or MFC), or QT, this will draw menus on top of OpenGL (using GDI, or other technology)
use some third party library that will draw GUI in OpenGL (using its rendering commands)
For the latter option and for simple GUI I suggest http://www.antisphere.com/Wiki/tools:anttweakbar
I had the same problem and I solved it using Win32API.
Use the CreateMenu function to create the menu, then use the SetMenu function to set the menu to the window.
Because when menu is set, the drawing area of the program will be reduced, causing the coordinates to be offset when the mouse is clicked. We need to resize the window using the AdjustWindowRect and MoveWindow functions.
Because opengl will take over the callback function of the window, the menu command we set cannot be accepted by the program, we need to use the SetWindowLongA function to set the callback function of the window to the function we defined, and use the CallWindowProc function in the last line of the function we defined to call the opengl callback function.
Here is a example code:
#define IDM_MENU_1 (1) // menu id
static WNDPROC gl_wnd_proc; // legacy opengl window proc function
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDM_MENU_1: // Do menu command here...
}
}
}
// Here we have to use `CallWindowProc` function
return CallWindowProc(gl_wnd_proc,hWnd, msg, wParam, lParam);
}
int main()
{
// do `glutInit` first ...
// 1. Create and set menu
HMENU hMenu = CreateMenu();
AppendMenuA(hMenu, MF_STRING, IDM_MENU_1, "Menu 1");
HWND hWnd = FindWindowA("GLUT", NULL); // "GLUT" is opengl window class name
SetMenu(hWnd, hMenu);
// 2. Adjust window size
RECT rt = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
AdjustWindowRect(&rt, GetWindowLongA(hWnd, GWL_STYLE), TRUE);
MoveWindow(hWnd, 0, 0, rt.right - rt.left, rt.bottom - rt.top, TRUE);
// 3. Set window callback proc function
gl_wnd_proc = (WNDPROC)SetWindowLongA(hWnd, GWLP_WNDPROC, (LONG)MyWndProc);
// do `glutMainLoop`
}
As for sub-menus, its creation method also continues to use CreateMenu and AppendMenu, you can refer to Win32 API C++ Menu bar

Why is my child window unresponsive to mouse events?

I have created a customized static window which displays a bitmap image, this window is the child window of some other window. Now I want to capture mouse events for this window, so that I can provide functionality to crop the image.
But the problem is Mouse events are not passed to this child window....
following is a code snippet of the WndProc of child window ..
WNDPROC origStatProc;
// Variable which stores the handle of BITMAP image
HBITMAP hBitmap=NULL;
LRESULT CALLBACK dispWndProc(HWND hwnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc;
static PAINTSTRUCT paintSt;
static RECT aRect;
switch(msg)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&paintSt);
GetClientRect(hwnd,&aRect);
if(hBitmap!=NULL)
{
HDC memDC = CreateCompatibleDC(hdc);
if(memDC!=NULL)
{
BITMAP bmp;
GetObject(hBitmap,sizeof(bmp),&bmp);
SelectObject(memDC,hBitmap);
SetStretchBltMode(hdc,HALFTONE);
StretchBlt(hdc,0,0,aRect.right,aRect.bottom,
memDC,0,0,bmp.bmWidth,bmp.bmHeight,
SRCCOPY);
DeleteObject(&bmp);
ReleaseDC(hwnd,memDC);
}
}
// the code for painting
EndPaint(hwnd,&paintSt);
}
break;
case STM_SETIMAGE:
{
InvalidateRect(hwnd,&aRect,true);
}
break;
case WM_LBUTTONDOWN:
{
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
char xstr[10];
_itoa(xPos,xstr,10);
MessageBox(NULL,xstr,"X Value ",MB_OK);
}
break;
default:
return origStatProc(hwnd,msg,wParam,lParam);
}
return 0;
}
Can anyone tell me what else I need to capture mouse events inside this Child window...
The window class that you use for the window will determine certain default behaviors for the window. The Static window class is particularly difficult to work with, because Windows makes assumptions that the window will never change its contents, and won't interact with the user in any way. You'll probably find that the WM_LBUTTONDOWN is being passed to the parent window.
If I remember correctly: static windows declare themselves to be 'invisible' to mouse clicks by returning HTTRANSPARENT in response to WM_NCHITTEST. Because of this, windows passes the mouse click on to the parent. If you want to process the mouse clicks in the statics, you'll need to also override this behavior to return HTCLIENT instead.
I have called DefWndProc() instead of origStatProc(hwnd,msg,wParam,lParam) and the problem is solved....
anyWays thanks to everyone....

c++ gdi animation not working

im trying to create ball animation using gdi but i can't get it working.
i created a ball using this
Graphics graphics(hdc);
Pen pen(Color(255, 0, 0, 255));
graphics.DrawEllipse(&pen, sf , 0, 10, 10);
i have while loop that loops and adds 1 to sf value basicly like this sf++;
than i try to repaint the window(it doesn't work) so ill end up with more than one circle ;/
here is the loop( the loop is int WM_PAINT)
while(sd==1)//sd equals 1
{
sf++;
onPaint(hdc);
InvalidateRect (hWnd, NULL, TRUE);// this should repaint the window but it doesn't
UpdateWindow(hWnd);
}
thanks in advance
Rami
In order to achieve animation I would suggest you use a timer. For example:
int OnCreate(HWND window, WPARAM wParam, LPARAM lParam)
{
SetTimer(window, TIMER_ID, 1000, 0);
return 0;
}
now window will receive WM_TIMER messages every second (1000ms). You should handle them:
int OnTimer(HWND window, WPARAM wParam, LPARAM lParam)
{
if(TIMER_ID == wParam)
{
/*do stuff*/
InvalidateRect(window, NULL, TRUE);//force window to repaint
}
return 0;
}
then you need to handle WM_PAINT message to do the drawing
int OnPaint(HWND window, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(&ps);
Graphics graphics(hdc);
graphics.Draw...
EndPaint(&ps);
return 0;
}
You do realize that you are incrementing sf in a loop with a conditional of (sd == 1), right? That will of course just loop infinitely or never be entered because the value of sd is not being changed in any way. Have you used the debugger at all here? Why would you need such a loop anyway? You should not be calling OnPaint in a loop.
If you want more than one circle, just draw them all before returning from the function. Maintain a collection of data that will be used to draw the circles in the OnPaint handler.
InvalidateRect sends a WM_ERASEBKGND message, and if you don't have a hbrBackground (brush to repaint the background) member of the WNDCLASS structure defined when you create the window it won't redraw the background unless you handle the WM_ERASEBKGND message yourself.
If that isn't the problem, then maybe because you are calling UpdateWindow directly instead of polling and handling messages, the WM_ERASEBKGND message never gets handled. Try overwriting the previous circle with the background colour before drawing the new one.
Or call SendMessage with WM_ERASEBKGRND as the message.
I found an example on msdn which shows how to draw stuff in pure win32.
You should not call Invalidate or Updatewindow in WM_PAINT, as UpdateWindow sends a new WM_PAINT-event, and invalidates get accumulated until the next wm_paint event.
You should divide your Code into two functions, one to perform the movement and the other to draw your circle at the current location.
Your Mover-function can be called from anywhere (perhaps in a timer handler function?) and should end with
InvalidateRect (hWnd, NULL, TRUE);
UpdateWindow(hWnd);
In order to mark your client area for redrawal and notify your window to redraw itself.
Your Draw()-function should read the position set with your mover function, and just a draw a circle around this location.
(Sidenote: If you want to minimize flicker and get smooth animation, have a look at double buffering once you get your basic animation up and running)
UPDATE
You were missing the UpdateWindow command in your Update-function
Your OnPaint-Function is only called when a WM_PAINT-message is received by your application, so you need to send those.
UpdateWindow serves this purpose
VOID update(HDC hdc,HWND hWnd)
{
sf++;
FillRect(hdc,rect,(HBRUSH)(COLOR_WINDOW+1));
InvalidateRect (hWnd, NULL, TRUE);
UpdateWindow(hWND);//<- This Line sends a wm_paint-message to your window in order to make it redraw itself
}
//i didn't do any changes to the onPaint functon but here is the code for it
VOID onPaint(HDC hdc)
{
Graphics graphics(hdc);
Pen pen(Color(255, 0, 0, 255));
graphics.DrawEllipse(&pen, sf , 0, 10, 10);
}
//here is the while loop
while(sd==1)
{ onPaint(hdc);
update(hdc,hWnd);
}