How to repaint a child window only once every frame using WinAPI? - c++

I'm using Direct3D and WinAPI to create windows and render 3D objects in the client area. I use the standard Windows message loop to invalidate the rectangle of the render window, and in the message handler of the render window, I perform a render call in Direct3D when processing the WM_PAINT message:
BOOL bRet;
HWND mainWnd; // Main window
HWND renderWnd; // Child of mainWnd, takes up a portion of the client area
// to be used as a Direct3D render target
MSG msg = {};
while ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if(bRet != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
InvalidateRect(renderWnd, nullptr, false);
}
}
// ...
// Window procedure used by renderWnd
LRESULT renderWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// ...
case WM_PAINT:
{
// Perform Direct3D rendering
// ...
}
break;
// ...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
This setup seems to work correctly as long as my app only has one window, as InvalidateRect is called each frame and ensures that the client area needs to be redrawn, which in turn will result in a Direct3D draw call. It doesn't feel very elegant though, especially once I try to create multiple windows, as I'd have to invalidate their rectangles in that same piece of code, even if the features that the windows serve otherwise have nothing to do with each other (some of the windows might not even exist at any one time).
That said, my question is this: is it possible to have a window invalidate part of its client area exactly once each frame (assuming it's currently not minimized, etc.)? Maybe through the use of the message queue? Referring back to the above code segment: I'd want some way for mainWnd (perhaps in its own window procedure) to call InvalidateRect on renderWnd exactly once each frame.
Thanks in advance!
EDIT: small error in the code sample

Note that the 'standard' way to handle this is something more like this:
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Update your simulation/animation/etc. based on elapsed time
// -or-
// multiple fixed time-steps.
//
// Then render one frame.
}
}
…
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
This model is a 'flat-out' rendering model where you will render as fast as the system can do it, limited by Present details like refresh rate and automatic throttling if you have 3 or more frames ready.
You should take a look at GitHub for some more details like implementing WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE.
The only time you'd implement WM_PAINT / InvalidateRect to render is if you are doing an editor or some 'mixed' UI and Direct3D application.

So with the help of the comments on the original post, I figured out that the best option was to use the Timers provided by WinAPI to schedule a repaint of the render window at the required framerate. Going to mark this as solved.

Related

How to detect hovering over a static Win32 control?

I'm having trouble detecting a hover over a static Win32 control.
This is not a duplicate issue because this looks for multiple static controls instead of just looking for a single known handle to a static control at compile time.
While this can be done in seconds in another language, I'm growing a little frustrated after trying things out for some hours. I hope to get an answer here.
First, I created a class called Label. I create a static control window within it. I'll refer to static as label for now on.
// Create the label's handle.
m_handle = CreateWindowEx(NULL, "static", m_text.c_str(),
WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (m_handle == NULL)
return false;
When the mouse hovers over this label, the following method should be called:
void Label::invokeOnMouseHover()
{
if (m_onMouseOver)
m_onMouseOver();
}
This will call my method:
void lblName_onMouseOver()
{
MessageBox::show("Hovering!", "My Console",
MessageBoxButtons::Ok, MessageBoxIcon::Information);
}
This is how I create it from the top level:
Label lblName("This is a label.", 0, 0);
lblName.setVisible(true);
lblName.OnMouseOver(lblName_onMouseOver);
frm.add(lblName);
Admit it, this thin layer is beautiful.
While my callbacks are working fine for my Button and Checkbox controls, I noticed that statics are a little different.
So, let's go down a few levels:
This is in the main window's procedure:
case WM_MOUSEMOVE:
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
frm.setMousePos(xPos, yPos);
// Get the static's id
int id = // ?? Which static control id is it out of several?
// Obtain the control associated with the id.
X3D::Windows::Control *ctrl = frm.getControls().find(id)->second;
if (ctrl == NULL)
return 0;
// Check if this is a X3D Label control.
if (typeid(*ctrl) == typeid(X3D::Windows::Label))
{
Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
if (xPos >= lbl->getX() &&
yPos >= lbl->getY() &&
(xPos < (lbl->getX() + lbl->getWidth())) &&
(yPos < (lbl->getY() + lbl->getHeight())))
{
if (lbl != NULL)
lbl->invokeOnMouseHover();
}
}
}
break;
What I'm trying to do here is detect what label id was detected, and then call Label::invokeOnMouseOver().
Even though I Understand I need to use TRACKMOUSEEVENT at some point, its field member 'HWND' requires the label's handle. But I can't easily say which handle it will be because the collection may contain one or several labels.
Overall, I'm looking for suggestions on how to either restructure this or see if there's an easy solution here. My guess is I'm overthinking this.
Thanks.
Update:
Here is a code update after reading the first answer with the first solution. While this solves the hover issue, I don't see the label's text on execution.
case WM_MOUSEMOVE:
{
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
// Get the mouse position
frm.setMousePos(xPos, yPos);
// Check for labels
X3D::Windows::Control *ctrl = (X3D::Windows::Control*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (ctrl)
{
// Check if this is a X3D Label control.
Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
if (lbl)
lbl->invokeOnMouseHover();
return CallWindowProc(lbl->getOldProc(), hWnd, msg, wParam, lParam);
}
}
break;
And the control creation:
// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
return false;
SetWindowLongPtr(m_handle, GWLP_USERDATA, (LONG_PTR)(X3D::Windows::Control*)this);
m_oldProc = (WNDPROC)SetWindowLongPtr(m_handle, GWLP_WNDPROC, (LONG_PTR)&wndProc);
If it's a paint issue, this is what I have in WndProc.
case WM_PAINT:
{
hDC = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
}
break;
Update #2:
The alternative solution fixed the issue.
If anyone has trouble with unresolved external symbols with SetWindowSubclass() in the future, remember to add the following to your project or just #pragma it:
#pragma comment(lib, "comctl32.lib")
The only identifying info that WM_MOUSEMOVE gives you is the HWND that the mouse is moving over (or the HWND that has captured the mouse). The reported X/Y coordinates are relative to that HWND. That is the HWND that you are looking for, so you don't need to hunt for it, the message gives it to you.
If you need access to an HWND's control ID, you can use GetDlgCtrlID() for that. But note that every HWND has its own window procedure, so control IDs are typically only useful for notification messages, like WM_COMMAND and WM_NOTIFY, which are sent to a control's parent window (and even then, such notifications also carry the child's HWND as well).
When the mouse moves over a particular HWND, WM_MOUSEMOVE is posted to the message procedure of that HWND only (or to the HWND that has captured the mouse). It sounds like you are expecting it to be posted to the control's parent window instead, and that is simply not the case. That is why your WM_MOUSEMOVE handler is not being called. You are handling the message at the wrong level. You need to be prepared to handle messages on a per-control basis instead, using the control's own message procedure.
It would be more efficient to store your Control object's this pointer inside its associated HWND itself, via SetWindowLongPtr(GWLP_USERDATA), SetWindowSubClass(), or SetProp(), and then your message handlers can access the Control* pointer of the message's reported HWND when needed, for example:
// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
return false;
SetWindowLongPtr(m_handle, GWLP_USERDATA, (LONG_PTR)(X3D::Windows::Control*)this);
m_oldproc = (WNDPROC) SetWindowLongPtr(m_handle, GWL_WNDPROC, (LONG_PTR)&MyWndProc);
...
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOUSEMOVE:
{
...
X3D::Windows::Control *ctrl = (X3D::Windows::Control*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (ctrl)
{
// Check if this is a X3D Label control.
Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
if (lbl)
lbl->invokeOnMouseHover();
}
break;
}
...
}
return CallWindowProc(m_oldproc, hWnd, uMsg, wParam, lParam);
}
Alternatively:
// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
return false;
SetWindowSubclass(m_handle, &MySubclassProc, 1, (DWORD_PTR)(X3D::Windows::Control*)this);
...
LRESULT CALLBACK MySubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &MySubclassProc, uIdSubclass);
break;
case WM_MOUSEMOVE:
{
X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;
// Check if this is a X3D Label control.
Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
if (lbl)
lbl->invokeOnMouseHover();
break;
}
...
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
This post doesn't answer the question you asked but you should read it. It is important, and it is posted in a spirit of helpfulness after my rather acid comment above. I hope you find it so.
This class library is going to run into trouble. Code like this (using a dynamic_cast):
case WM_MOUSEMOVE:
{
X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;
// Check if this is a X3D Label control.
Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
if (lbl)
lbl->invokeOnMouseHover();
break;
}
Is almost always wrong.
Why? Well, suppose you want to hover over some other kind of control? What are you going to do now? And these guys are just going to multiply like rabbits, so don't do that.
Instead, for a message that the library understands (such as this one), declare a corresponding virtual method in the base class that derived classes can override if they're interested in processing that message. Then you have the basis of a solid design (and this is pretty basic stuff).
So, in this case you would have:
class Control // Base class
{
...
virtual void onMouseHover (...) { }
...
};
And then:
class Label : public Control // Derived class
{
...
virtual void onMouseHover (...) override { ... }
...
};
Now for my second point: you are going to find that, particularly for dialogs, your application is going to want to handle a lot of messages that the base class doesn't understand (or care about).
How are you going to do this? Are you going to add code to the base class for each new message that your application (or for that matter specific types of control implemented in the class library) becomes interested in? That is not a very attractive prospect.
Now MFC handles this with something it calls a message map, which is essentially a table of message ID's and their corresponding command handlers which you can associate with (in your case) any object ultimately derived from Control and I recommend you do something similar.
But thanks to the magic of the STL, you can do better. I have something like this in my class library (my base class is actually called Window, as I would suggest yours should be):
typedef INT_PTR (Window::*MESSAGE_HANDLER)
(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Register a message handler
void Window::RegisterMessageHandler (UINT uMsg, MESSAGE_HANDLER handler);
And what RegisterMessageHandler() actually does is to add handler to a std::unordered_map associated with the Window object using uMsg as a key. Then, when that message subsequently comes in, it can be dispatched to the right handler without the base class knowing anything about the meaning of the message whatsoever, and that's what you're going to need.
So, you might declare the following in class Control (code untested, written in Notepad):
class Control // Base class
{
...
std::unordered_map <UINT, MESSAGE_HANDLER> m_message_map;
...
};
And then RegisterMessageHandler() might look like this:
void Window::RegisterMessageHandler (UINT uMsg, MESSAGE_HANDLER handler)
{
m_message_map.emplace (uMsg, handler);
}
And MySubclassProc() might look like this:
LRESULT CALLBACK MySubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;
auto handler ctrl->m_message_map.find (uMsg);
if (handler != ctrl->m_message_map.end ())
return handler.second (hWnd, uMsg, wParam, lParam);
...
}
My own class library is actually more sophisticated than this (I started with something simple but then embellished it over time) but that's the basic idea. You might have to master a few C++ skills to pull this off but trust me, if you implement something like this you'll be very glad you did, down the line.

How to block mouse input from transparent window with Win32 API?

I have a main window in a process that is not owned by the program I'm creating. I'm using a Windows Hook to inject a DLL into this process for the purpose of adding a child window to this main window.
My end goal was to create a WS_EX_LAYERED window that allows me to create an internal colored border but allow the center portion to be transparent and allow mouse clicks through. This part works perfectly.
WNDCLASS wndClass = {};
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = OverlayProc;
wndClass.hInstance = g_TargetInstance;
wndClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 255, 255));
wndClass.lpszClassName = "OVERLAY";
RegisterClass(&wndClass);
g_Window = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, "OVERLAY", nullptr,
WS_CHILDWINDOW, rect.left, rect.top, rect.right+1, rect.bottom+1, data->hwnd, nullptr, g_TargetInstance, nullptr);
SetLayeredWindowAttributes(g_Window, RGB(0, 255, 255), 0, LWA_COLORKEY);
ShowWindow(g_Window, SW_SHOW);
UpdateWindow(g_Window);
The 2nd part to this is a I wanted to conditionally block all mouse input to the parent window. I couldn't do this with the transparent portion of the WS_EX_LAYERED window so I tried creating a 2nd transparent STATIC control as a child of the main window but this doesn't block mouse input either.
I'm also sending simulated mouse clicks to the parent window through calls to PostMessage, passing WM_LBUTTONDOWN and WM_LBUTTONUP. How could I block all mouse input to the parent window via a transparent window?
It appears this is not possible to do with a simple transparent window drawn over sibling controls. What I ended up doing was using SetWindowHookEx to add a WH_GETMESSAGE hook into the process from which I use to replace the main window's WndProc function and intercept mouse messages. I tag my simulated mouse messages with a specific value in the wParam argument so the proc will now it was simulated and removes that value, passing it along to the parent window.
If it does not detect my "tag" value in the click message, it will swallow the mouse message and not pass it along to the original WndProc function.
Injected WndProc replacement
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
wParam -= 11141008;
if (wParam != MK_LBUTTON && !g_Paused)
return 0;
break;
case WM_LBUTTONUP:
wParam -= 11141008;
if (wParam != 0 && !g_Paused)
return 0;
break;
case WM_MOUSEHOVER:
case WM_MOUSEMOVE:
if (!g_Paused)
return 0;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Snippet from Windows Hook function
//...
switch (data->message)
{
case (WM_USER + 1):
{
g_Paused = FALSE;
//...
SetWindowSubclass(data->hwnd, WndProc, 1, 0);
break;
}
case (WM_USER + 2):
{
RemoveWindowSubclass(data->hwnd, WndProc, 1);
//...
break;
}
}
//...
The code inside the window hook function is used to subclass the main process window and inject my own WndProc function which in turn processes mouse input the way I want.
This is the code used to "simulate" mouse clicks without physically clicking in the window. Note the added value to wParam to identify this click as simulated and not generated by the user.
void Window::LeftClick(DWORD x, DWORD y, DWORD delayMillis)
{
LPARAM lparam = MAKELPARAM(x, y);
lock_guard<mutex> lock(this->m_ClickMutex);
PostMessage(this->m_Window, WM_LBUTTONDOWN, 11141008 + MK_LBUTTON, lparam);
this_thread::sleep_for(std::chrono::milliseconds(delayMillis));
PostMessage(this->m_Window, WM_LBUTTONUP, 11141008, lparam);
}
Also, just for the person in the comments who was ridiculing my choice of the word simulated and the added criticism for using PostMessage to simulate keyboard input, here is my keyboard input test method which (for my purposes) works flawlessly and very reliably
void GameWindow::KeyPress(UINT vkCode) const
{
UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC);
LPARAM lparam1 = MAKELPARAM(1, scanCode);
LPARAM lparam2 = MAKELPARAM(1, 0xC000 | scanCode);
PostMessage(this->m_Window, WM_KEYDOWN, vkCode, lparam1);
this_thread::sleep_for(chrono::milliseconds(25));
PostMessage(this->m_Window, WM_KEYUP, vkCode, lparam2);
}

C++ WinApi Fillrect() crashes (multiple rects)

i am trying to get used to WinApi and decided to make a GUI for a sudoku-generator i programmed.
It should adjust dynamicly to the windowsize the user chooses.
So far everything works as inteded, but if the WM_PAINT-msg is sent too often in a short window of time (eg changing the size of the window) the program crashes.
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
stringstream ss; //not used
RECT rect;
int w;
int h;
HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
switch (message)
{
case WM_SIZE: //
{
GetWindowRect(hwnd,&rect);
menu.wndw=rect.right-rect.left; //menu is a class to store important information
menu.wndh=rect.bottom-rect.top;
h=menu.wndh;
w=menu.wndw;
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
menu.feld[i][j].SetSpace((w/4)+((i-1)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j-1)*(h/20))+j+(2*((j-1)/3)),(w/4)+((i)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j)*(h/20))+j+(2*((j-1)/3)));
}
} //feld is a class wich exists in a 10x10 array with the 0s not being used
InvalidateRect(hwnd,NULL, TRUE);
}
break;
case WM_PAINT:
{
RECT re;
w=menu.wndw;
h=menu.wndh;
hdc = BeginPaint(hwnd,&ps);
re.left=(w/4)-4;
re.top=(h/4)-4;
re.right=(w/4)+9*(w/20)+18;
re.bottom=(h/4)+9*(h/20)+18;
FillRect(hdc,&re,CreateSolidBrush(RGB(0,0,0)));
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
re=menu.feld[i][j].GetSpace();
if(menu.feld[i][j].GetSelect()==uns)
if(FillRect(hdc,&re,coluns)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==mso)
if(FillRect(hdc,&re,colmso)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==sel)
if(FillRect(hdc,&re,colsel)==0)
MessageBox(hwnd, "fail","fail",0);
}
}
EndPaint(hwnd, &ps);
}
break;
http://www.pic-upload.de/view-22113118/Unbenannt.png.html
here is a picture of what the executed program looks like.
Now as described earlier the program will crash if u change the windowsize in a lot of small steps. After calling the MW_PAINT msg for ~10 times the window will just freeze with 1 of the rects being white instead of the desired color (random one, different every time).
my assumption is that i need to release some kind of resources because mby a stack will overflow or smth, but i have really no idea where i could have a leak in my program.
i would be very grateful if anyone could help me.
You create three brush handles every single time your window procedure executes. These handles are never tidied up. And then inside the WM_PAINT handler, you create a brush which you pass to FillRect and so can never destroy it.
So you leak three handles every time the window procedure executes (which happens a lot), and one more every time it handles WM_PAINT. Simply put, your program leaks like a sieve!
You should consider creating these brushes when the window is created, and destroying them when the window is destroyed. Or perhaps creating them inside the WM_PAINT handler, and destroying them as soon as you have finished using them. But since they have constant colors it is probably best to create 4 brushes up front, once and for all.
You are leaking GDI resources as member David Heffernan said.
Here is the example of how to properly use brushes in your application-pay attention to WM_COMMAND handler in that example.
If you do not use stock GDI objects you must delete them after you are done working with them.
Here is the simple example that fills window with red brush in WM_PAINT handler:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPain( hdc, &ps );
HBRUSH hbrRedBrush = CreateSolidBrush( RGB( 255, 0, 0 ) );
RECT r;
GetClientRect( hWnd, &r );
FillRect( hdc, &r, hbrRedBrush );
DeleteObject( hbrRedBrush ); //you must delete GDI object!
EndPaint( hWnd, &ps );
}
return 0L;
In your case, I would make 4 static brushes and rework my code a little, adding the proper cleanup in WM_CLOSE handler. Below are the suggested changes:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
// add static before HBRUSH
static HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
static HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
static HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
static HBRUSH BlackBrush = CreateSolidBrush(RGB(0,0,0));
switch (message)
{
// this is the problematic handler
case WM_PAINT:
{
//the changed part
FillRect( hdc, &re, BlackBrush );
}
break;
case WM_CLOSE:
{
DeleteObject( BlackBrush );
DeleteObject( coluns );
DeleteObject( colsel );
DeleteObject( colmso );
// other clean up code
}
break;
IMPORTANT NOTE:
This time you used FillRect API, but next time you might load bitmaps and other stuff that require from you to restore HDC into original state after you are done with drawing.
You do that like this:
HBITMAP bmpOld = (HBITMAP)SelectObject( hdc, myBitmap );
// bmpOld stores the original state of the device context
// you do something with myBitmap
// then you return device context into original state
// by selecting the original value, bmpOld, back into device context
SelectObject( hdc, oldBmp );
DeleteObject( myBitmap );
Again, pay attention to WM_COMMAND handler in the above MSDN example to see how they did it.
Here is the link to a great Win32 API tutorial for beginners-give it a go.
In the end I recommend you this tool for detecting GDI leaks.
If you have further questions leave a comment and I will reply as soon as possible.
Best regards and good luck!

Remove the standard window frame in C++ Win32

I saw this documentation on MSDN.
I am trying to remove the standard frame of the window. I successfully extended the frame into client area, but the following snippet does not work. My window looks exactly the same as without it....
if (message == WM_CREATE)
{
RECT rcClient;
GetWindowRect(hWnd, &rcClient);
// Inform the application of the frame change.
SetWindowPos(hWnd,
NULL,
rcClient.left, rcClient.top,
(rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top),
SWP_FRAMECHANGED);
}
Could anybody help me please?
I think you can do it by passing WS_OVERLAPPED (not WS_OVERLAPPEDWINDOW) as the dwStyle parameter to CreateWindowEx when creating the window.
It's really simple, just go to your window procedure, then the message WM_NCCALCSIZE and return 0 when WPARAM is TRUE
// Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_NCCALCSIZE:
if (wparam == TRUE) return 0;
break;
}
...
}
As a clarification the code that you showed serves to force the previous code

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);
}