Draw changeable text with CDC::DrawText - c++

I want to show on the screen some value, that are changeable. I have following code
void CMainWnd::OnPaint()
{
CPaintDC dc(this);
CRect rcText( 0, 0, 500 ,500 );
wchar_t text[36];
unsigned int num = server->GetNumClients(num);
wsprintf(text, L"Number of connected clients: %d", num);
dc.DrawText(text, &rcText, DT_LEFT);
CFrameWnd::OnPaint();
}
void CMainWnd::OnTimer(UINT timerID)
{
SendMessage(WM_PAINT, 0, 0);
}
It draws text when window appears. But in next calls when text is different the text on the screen didn't change. Using the debugger I can see that OnPaint was called, text has been changed, but on my window text remains the same. GetLastError() returns 0. I think I'm missing something important how DrawText works. I tried to call UpdateWindow() in the end, but nothing changed. For some reason screen is not updates..

You should not send a paint message directly, but instead invalidate the area to be repainted (InvalidateRect(&area) ) and let the system handle it. By only sending a paint, you don't get anything because the system says 'There's no area that needs painting, so for efficiency I won't bother' - or rather, the clip area that constrains painting will be empty (no update area). By invalidating an area you tell the system that that area needs repainting, so the next paint call will have a valid clip area and you will see a change.
(Better to use wsprintf_s() with the buffer size - in fact, as you appear to be using MFC use CString and CString::Format() instead - and you should not call the base class OnPaint() (it has no effect, since when the CPaintDC goes out of scope it clears any update area).

Related

How to detect if painting last frame in buffered paint animation?

I'm using BeginBufferedAnimation() during WM_PAINT to animate a custom control (cross-fade).
I know when the first frame of the animation is painted; when I call EndBufferedAnimation() with fUpdateTarget = TRUE.
I can determine if the animation is in progress by checking the return value from BufferedPaintRenderAnimation().
Question is: how do I know when the last frame of the animation is painted?
I couldn't find an API call that can do this.
One thing that comes to mind, is to use GetTickCount() to determine the time that elapsed since the call to EndBufferedAnimation() and check that against the dwDuration member of the BP_ANIMATIONPARAMS struct.
However, I'm not sure if this method is very accurate.
Is there another (foolproof) way to determine if WM_PAINT is painting the last frame of the animation?
EDIT
Obviously, checking the elapsed time doesn't work when the animation is prematurely stopped by a call to BufferedPaintStopAllAnimations() or invalidating the part of the client area that is being animated.
EDIT 2
This is my (simplified) WM_PAINT code:
PAINTSTRUCT ps;
HDC DC = BeginPaint(Handle, &ps);
if (DC != NULL)
{
// If animation in progress, paint the next frame.
if (!BufferedPaintRenderAnimation(Handle, DC))
{
BP_ANIMATIONPARAMS ap = {sizeof(ap)};
ap.style = BPAS_LINEAR;
ap.dwDuration = 1000;
RECT R;
GetClientRect(Handle, &R);
HDC hdcFrom, hdcTo;
HANIMATIONBUFFER Animation = BeginBufferedAnimation(Handle, DC, &R, BPBF_COMPATIBLEBITMAP, NULL, &ap, &hdcFrom, &hdcTo);
if (Animation)
{
if (hdcFrom) Paint(hdcFrom, &R, OldState);
if (hdcTo ) Paint(hdcTo, &R, NewState);
// Paint the first frame.
EndBufferedAnimation(Animation, true);
}
else
Paint(DC, &R, NewState);
}
else
{
// Here, I want to check if BufferedPaintRenderAnimation() painted the last frame.
}
EndPaint(Handle, &ps);
}
EDIT 3
My custom control has a child control, which needs to be animated in sync with its parent. For this purpose, I'm letting the child control paint itself into the first and last animation frame by sending it a WM_PRINT message inside my Paint() method. The child control receives its WM_PAINT message after the parent is painted. To prevent the child control from painting while the parent is being animated, I wanted to hide the child control when I start the animation and show it again after the animation finished.
Since I couldn't find a foolproof way to detect when the animation finishes, I decided not to hide the child control. Instead, I avoid repainting the child control with RedrawWindow(ChildHandle, NULL, NULL, RDW_VALIDATE | RDW_NOFRAME) after the call to EndBufferedAnimation() and when BufferedPaintRenderAnimation() returns true. This way,
BufferedPaintRenderAnimation() paints the child control in its final state when the animation finishes, so the child control doesn't have to.
I found a better solution to my problem.
See EDIT 3.

How to get the handle of the active window in win32 using c++?

[![enter image description here][1]][1]I am trying to capture the active window in Win32 using C++. With the BitBlt function I am able to capture, but once another window opens, the same window which I have already captured should only be captured. I don't want the other window which I have opened, it should be black. Can someone help with a solution?
https://www.codeproject.com/Articles/20367/Screen-Capture-Simple-Win32-Dialog-Based
void CaptureActiveWindow(void)
{
RECT ActWndRect;
WCHAR buf [100],buf1[20];
int xSrc=0,ySrc=-19;
int DepcWidth=10, DepcHeight=5;
OutputDebugString(L"Start capture act window ");
HDC ActWndDC = GetDC(hWndActWnd); //DC for the window you have clicked on
MemDC = CreateCompatibleDC(ActWndDC); //Memory DC Compatible with Above DC
GetWindowRect(hWndActWnd,&ActWndRect); //Will Store the Windows Are in Rectangle
wsprintf(buf,L"x1 = %d , y1 = %d, x2 = %d y2 =%d",ActWndRect.left,ActWndRect.top,ActWndRect.right,ActWndRect.bottom);
OutputDebugString(buf);
int Width = ActWndRect.right-ActWndRect.left; //Width of the Window
int Height =ActWndRect.bottom-ActWndRect.top; //Hight of the Window
if(GetWindowText(hWndActWnd,buf1,20) >0)
{
OutputDebugString(buf1);
}
if(CaptureControl)
{
ySrc= DepcWidth = DepcHeight = 0;
}
HBITMAP hBitmap = CreateCompatibleBitmap(DlgDC,Width-DepcWidth,Height-DepcHeight);//Will Create Bitmap Comatible With Our Window
SelectObject(MemDC,hBitmap);
BitBlt(MemDC,0,0,Width,Height,ActWndDC,xSrc,ySrc,SRCCOPY);//Will Copy the Window into MemDC
//BitBlt(DeskDC,110,110,Width,Height,MemDC,Begpt.x,Begpt.y,SRCCOPY);
SaveBitmap(MemDC, hBitmap,"Sample.bmp"); // will Save DC into .bmp File
ShowImage(); //Will Show u the .bmp File in MSPAINT.
}
Hook the mouse event Before sending active message to the window. Use WindowFromPoint to get the specified window(Hwnd). Then use GetWindowRect to get the window rect area. In this area, call WindowFromPoint for all the point in the rect, compare it with Hwnd(if it is a child window or not), and get the overlap RECT. After getting the bitmap of the capture window and then overwrites the black on the covered rect.
PS: I encounter BITMAPINFO error: Run-Time Check Failure #2 - Stack around the variable was corrupted.
Here provide a solution.
You can't capture the image of Chrome using BitBlt(), unless disable the Hardware Acceleration option of Chrome. But PrintWindow() works with PW_RENDERFULLCONTENT flag. When use it, the image in center will have a black border. While using PrintWindow (hWndActWnd,ActWndDC,0x00000003) align the image to the left.Then modify cx and cy of CreateCompatibleBitmap(), you can remove the border easily.

Windows API SetWindowSize() seems to have no effect

I have what should be an extremely simple goal yet it seems intractable. I have to get some precisely-sized screen pix for documentation so I thought it would make sense to add a control to size my app's window to the exact dimensions I want.
I'm working with VS2010.
Here's the relevant code from my wizard-generated dialog:
DlgSetWindowSize::DlgSetWindowSize(CWnd* pParent /*=NULL*/)
: CDialogEx(DlgSetWindowSize::IDD, pParent)
{
m_width = 0;
m_height = 0;
m_parent = pParent;
}
void DlgSetWindowSize::OnBnClickedOk()
{
CDialogEx::OnOK();
SetWindowPos(m_parent, 0, 0, m_width, m_height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
}
and here is the call to it:
void CMyAppView::OnWindowSize()
{
DlgSetWindowSize d(this);
if (IDOK == d.DoModal())
{
Invalidate();
}
}
SetWindowPos returns a nonzero value, which indicates success according to the documentation (click here). Of course when running the dialog, I enter the pixel values I want for width and height. The debugger verifies that the expected values are being passed to SetWindowPos, and also that SetWindowPos gives a nonzero return. The bit switches in the last parameter to SetWindowPos are set to ignore the position parameters and only express the size parameters in that call, so that the window should be sized as I want without changing position.
Everything appears to be in order, but the window size doesn't change. I have applied this logic to my app's document window, and when that didn't work, I also applied it to the application's MainFrame window. Zero action.
Am I missing something here, or is there some completely different approach I should be using?
Judging by your use of CDialogEx and the naming convention, I guess you are using MFC, right?
Your call to SetWindowPos() operates on the dialog window itself, as this is a class method.
If you want to call parent's SetWindowPos(), you could do:
m_parent->SetWindowPos(0, 0, 0, m_width, m_height,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);
Also please note that in MFC Document-View architecture, the document doesn't have a window.
Alternatively, you could use Win API call:
::SetWindowPos(m_parent->GetSafeHwnd(), 0, 0, 0, m_width, m_height,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOOWNERZORDER);

Client rectangle coordinates on screen

How can I get coordinates of a window's client area relative to screen?
I thought about using GetClientRect and ClientToScreen. Also, in a browser window what is ClientRect? Only rectangle with HTML document shown in it, or it includes browser bars and pop-up menus, that can possibly shrink dimension for HTML doc?
I've tried this:
HWND hWnd;
RECT rc;
if (GetClientRect(hWnd, &rc)) // get client coords
{
MapWindowPoints(hWnd, NULL, reinterpret_cast<POINT*>(&rc), 2); // converts rect rc points
return rc.top;
}
But the sad thing is that browser's client rectangle includes all those pop-up browser menus and bars, therefore can't be used to detect accurate coordinates of browsers HTML document space. If anyone got suggestions how it can be done, will try it gladly.
Yes, you can do this with the ClientToScreen function:
RECT rc;
GetClientRect(hWnd, &rc); // get client coords
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left)); // convert top-left
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right)); // convert bottom-right
What is the "client" rectangle in a browser depends on the browser implementation. You can use Spy++ to discover this for yourself.
To translate a window's client rectangle to screen coordinates, call the MapWindowPoints function. It implements special handling to always return a valid RECT, even when used in scenarios that involve windows with right-to-left layout:
If hWndFrom or hWndTo (or both) are mirrored windows (that is, have WS_EX_LAYOUTRTL extended style) and precisely two points are passed in lpPoints, MapWindowPoints will interpret those two points as a RECT and possibly automatically swap the left and right fields of that rectangle to ensure that left is not greater than right.
Calling ClientToScreen on both points in contrast fails to account for RTL layouts, and can produce an invalid RECT. It fails to adhere to one of the rectangle coordinate invariants:
The coordinate value of a rectangle's right side must be greater than that of its left side. Likewise, the coordinate value of the bottom must be greater than that of the top.
A reliable function to return a window's client rectangle in screen coordinates would look like this:
RECT client_rect_in_screen_space(HWND const hWnd) {
RECT rc{ 0 };
if (!::GetClientRect(hWnd, &rc)) {
auto const err_val{ ::GetLastError() };
throw std::system_error(err_val, std::system_category());
}
::SetLastError(ERROR_SUCCESS);
if(::MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rc), 2) == 0) {
auto const err_val{ ::GetLastError() };
if (err_val != ERROR_SUCCESS) {
throw std::system_error(err_val, std::system_category());
}
}
return rc;
}
The question update asks for a different, unrelated issue. There is no API built into the system, that allows you to query a web browser's display area for its HTML content. The most promising solution would be to employ UI Automation. The question, however, is too broad to provide a more detailed answer here.
As commented by Raymond Chen, the preferred way of doing this should be something like the following:
inline POINT get_client_window_position(const HWND window_handle)
{
RECT rectangle;
GetClientRect(window_handle, static_cast<LPRECT>(&rectangle));
MapWindowPoints(window_handle, nullptr, reinterpret_cast<LPPOINT>(& rectangle), 2);
const POINT coordinates = {rectangle.left, rectangle.top};
return coordinates;
}
POINT origin;
origin.x = 0;
origin.y = 0;
ClientToScreen(hWnd, &origin);
Now origin is, in screen coords, the top left corner of the client area.
To convert (x,y) from client-area coords to screen coords, add origin.
To do the reverse, subtract.

Clear GDI shape inside the loop

I have a program which draw a Rectangle under mouse cursor and show the pixel color, but I can't manage it to clear the shape inside the while loop, if I use 'InvalidateRect()' it clear rectangle too fast and flickering, if not use 'InvalidateRect()' then Rectangle keep duplicating like THIS, how to fix that?
HWND hwnd;
POINT p;
unsigned short R=0, G=0, B=0;
void drawRect()
{
GetCursorPos(&p);
HDC hdc = GetDC(NULL);
HPEN border = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
HBRUSH background = CreateSolidBrush(RGB(R, G, B));
SelectObject(hdc, border);
SelectObject(hdc, background);
Rectangle(hdc, p.x+10, p.y+10, p.x+40, p.y+40);
DeleteObject(border);
DeleteObject(background);
}
void init()
{
while (GetAsyncKeyState(VK_RBUTTON) & 0x8000)
{
grabPixel(); //get RGB color from cursor coordination
drawRect(); //draw preview rectangle under cursor
InvalidateRect(hwnd, NULL, true);
}
}
Note: it doesn't have WinMain() or WndProc()
There are all sorts of things wrong with this. What are you actually trying to do?
From the fact that you're using GetDC(NULL), it looks like this is supposed to be drawing a rectangle on the entire screen.
Where is the hwnd value coming from? If that window does have a message loop (and it probably does), then that's the window being invalidated and redrawing itself.
A note: InvalidateRect merely marks the rectangle as needing-to-be-painted the next time that that application's (actually thread's, more-or-less) message queue is empty. UpdateWindow will cause a WM_PAINT message to be sent immediately.
drawRect isn't cleaning up properly, either. It should call ReleaseDC when it's finished, and it ought to restore the previous drawing objects after it's finished (and most definitely before it deletes them) as well:
HBRUSH oldBackground = SelectObject(hDC, background);
// ...
SelectObject(hDC, oldBackground);
What you probably want to do is, when selection starts, create a window the size of the screen and copy the existing screen into it. Then you can draw all over that intelligently.
The DrawDragRect function (see my blog) is designed for this sort of thing.