Using FillRect() in C++ - c++

I am new to using Graphics in Visual C++. I am just trying to make a rectangle filled with a color. Need help to correct this...
RECT rect;
HDC hdc;
hdc=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
rect.left=30;
rect.right=100;
rect.top=50;
rect.bottom=200;
FillRect(hdc,&rect,(HBRUSH)(RGB(40,151,151)));
The error is:
ERROR: The variable 'rect' is being used without being initialized.

This will normally be a warning, not an error. In this case, it also appears to be spurious.
It might work better if you initialize it something like:
HDC hdc=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
RECT rect = {30, 50, 100, 200};
HBRUSH brush = CreateSolidBrush(RGB(50, 151, 151));
FillRect(hdc, &rect, brush);
DeleteObject(brush);
Do note the use of CreateSolidBrush -- casting a color to an HBRUSH seems unlikely to work.

Your code fails because of this code:
(HBRUSH)(RGB(40,151,151))
You cannot cast an RGB color to an HBRUSH in any meaningful way. The only way to obtain an HBRUSH is a ask the system to give you one.
So, you need to create a real brush using one of the API functions for that purpose. For example, CreateSolidBrush.
HBRUSH hBrush = CreateSolidBrush(RGB(40,151,151));
When you have finished with the brush, call DeleteObject to return resources to the system.
As a general rule, every time you write a cast, regard the code as very suspicious. Always endeavour to write code without casts.

Related

Please confirm the best way to Restore the DC when a custom Pen and a custom Brush are selected

Can someone confirm if this sample code from Microsoft fails to restore the custom brush set with SetDCBrushColor?
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// Initializing original object
HGDIOBJ original = NULL;
// Saving the original object
original = SelectObject(hdc,GetStockObject(DC_PEN));
// ...
SelectObject(hdc, GetStockObject(BLACK_PEN));
Rectangle(hdc,0,0,200,200);
SelectObject(hdc, GetStockObject(DC_PEN));
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(255,0,0));
SetDCPenColor(hdc, RGB(0,0,255));
Rectangle(hdc,100,300,200,400);
SetDCBrushColor(hdc, RGB(0,255,0));
Rectangle(hdc,300,150,500,300);
// Restoring the original object
SelectObject(hdc,original);
}
break;
//...
Paul Watt, and other posters, suggest we use SelectObject to restore changes to the pen and brush separately, or that we use SaveDC and RestoreDC.
https://www.codeproject.com/Articles/224754/Guide-to-Win32-Memory-DC
// Setup paint for first layer.
HGDIOBJ hOldBrush = ::SelectObject(hDC, hBrush);
HGDIOBJ hOldPen = ::SelectObject(hDC, hPen);
HGDIOBJ hOldFont = ::SelectObject(hDC, hFont);
HGDIOBJ hOldMan = ::SelectObject(hDC, hBmp);
// ... Paint a motley display
::SelectObject(hDC, hOldBrush);
::SelectObject(hDC, hOldPen);
::SelectObject(hDC, hOldFont);
::SelectObject(hDC, hOldMan);
Or use SaveDC and RestoreDC to make it easy:
// Take a snap-shot of the current state of the DC
//https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-savedc
int SaveDC(
__in HDC hdc, // Handle to the DC
);
// Restore the DC to a previously saved state
int RestoreDC(
__in HDC hdc, // Handle to the DC
__in int nSavedDC // Saved state claim ticket
);
I realize that I need to use DeleteObject on any brushes/pens I create that are not stock objects.
Did Microsoft forget to use SelectObject with a previously saved version of the original brush? (Or should Microsoft have used SaveDC and RestoreDC?)
Did Microsoft forget to use SelectObject with a previously saved
version of the original brush?
I would say: Yes, they did!
In the case of the SetDCPenColor call, there isn't a problem, as restoring the original (saved) pen will revert the changes made. It seems that the example forgets to save (and subsequently restore) the original brush; if this is a custom brush, then simply restoring the brush colour with SetDCBrushColor would (IMHO) not be sufficient restoration.
But the issue doesn't end there! The linked example has also 'forgotten' to call EndPaint! From here:
Each call to BeginPaint must have a corresponding call to the EndPaint
function.
Or should Microsoft have used SaveDC and RestoreDC?
For both convenience and code safety, I would say this is the best policy: saving and restoring the entire DC state(s) avoids any issues that may later arise if/when additional changes to the DC are made in future code revisions. Bracketing your code in SaveDC() and RestoreDC() calls also has the advantage of restoring font colours, text modes, mapping modes, et cetera.
However, for code that may possibly be executed extremely frequently, saving and restoring only the components you actually change may show performance improvements (especially on older or slower processors).

C++ - two times DrawText()

I'm currently experiencing an error with my program.
My program has two rectangles, each of them surrounded by a groupbox.
Currently I'm trying two place text in each of them.
I've already got text in the first rectangle - fine (with DrawText()).
If I'm trying to display text in the second rectangle (also with DrawText()), the text is not displaying.
Here's the code I'm using:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, font);
DrawText(hdc, lpcwstr, wcslen(lpcwstr), &rect, DT_LEFT);
DrawText(hdc, lpcwstr, wcslen(lpcwstr), &rect_2, DT_LEFT);
EndPaint(FindWindow(NULL, L"Statistik (seit dem 01.01.2015)"), &ps);
Unfortunately I have no idea why the text is not displaying as expected.
Does anybody of you have a suggestion why this doesn't work?
[SOLUTION]
I was able to figure out what the problem was.
Not visible in the snippet, I posted initially, but the coordinates I set for the rectangles, were wrong.
Sadly I were not aware that all values are coordinates.
The only difference between the two calls is the RECT that you pass. The obvious conclusion is that you initialised one of the rectangles incorrectly.
You should restore the original font before calling EndPaint. And the call to FindWindow should be removed. Pass hwnd. Finally, your code performs no error checking at all. That's always imprudent.

Win32 DrawText stange aligment issue

Using Win7 x64 c++ with MSVC2010 pro.
I have noticed a really strange bug when using the Win32 DrawText to draw some text for a custom control. Its a pretty standard thing to do I'm sure. I did see a post about something similar and the solution was to use one the TextOut calls, but that doesn't resolve my issue.
I've subclass the "Static" control using the SetWindowSubClass and I'm hanlding the wm_paint message as:
case WM_PAINT:
{
RECT rect;
PAINTSTRUCT ps;
HDC hdc = BeginPain(hWnd,&ps);
// Create a back buffer to draw to
HDC hdcBack = CreateCompatibleDC(hdc);
GetClientRect(hWnd,&rect);
HBITMAP hbmBackbuffer= CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
size_t iLength = 0;
StringCchLength(LCDText,240,&Length);
SelectObject(hdcBack,hbmBackbuffer);
// Draw a black background to clear previous text
SelectObject(hdcBack,GetSysColour(1)); // Black
Rectangle(hdcBack,rect.left,rect.top,rect.right,rect.bottom);
// Set the font, tranparency and text colour
SelectObject(hdcBack,LCDFont);
SetBkMode(hdcBack,TRANSPARENT);
SetTextColor(hdcBack,0x0000ff00);
DrawText(hdcBack,LCDText,(int)iLength,&rect,DT_LEFT);
// display
BitBlt(hdc,0,0,rect.right,rect.bottom,hdcBack,0,0,SRCCOPY);
// cleanup
DeleteObject(hbmBackbuffer);
DeleteDC(hdcBack);
EndPaint(hWnd,&ps);
break;
}
This actually works very well. The problem is that the the 'label' can display 3 lines of 40 chararcters, and after the 27 character of each line the next chars to the end of that line are 1 or 2 pixels higher up the screen. It's not immediately apparent but once you notice it then it kindof draws your attention.
Does anyone have any ideas or experience with this?
ps - I typed the code in manually into the forum so there may be some silly typos but the real code does work properly apart the alignment issue.
Regards
Dave.

BitBlt issues with Memory DC created from printer DC

i have an issue with a fix i made to allow a flood filled object be printed...
so, the full story is we were using the windows GDI FloodFill function, which we noticed doesnt work on printers, so what i found on the inet, was to create a memory DC, compatible with the printer DC, and make all my drawing operations on the memory DC, and then BitBlt it all at once to the printer DC (i had to change to use a recursive, color replacment flood fill function too, since the memory DC only allows what the main DC did)
the problem is the memory DC seems to be a pixel or two bigger on the x and y, but i dont know what to do, when i get the selected bitmap from the memory DC, it shows it to be the correct size, i would like to use StretchBlt, but the values i have access to use as params for StretchBlt, make it no different than calling BitBlt
let me know if you need more info...
thanks in advance!!!
heres my code:
HDC hMemPrnDC = CreateCompatibleDC (hPrnDC);
HBITMAP hBitmap = CreateCompatibleBitmap (hPrnDC, iWidthLP, iHeightLP);
HBITMAP hOldBitmap = SelectBitmap (hMemPrnDC, hBitmap);
// paint the whole memory DC with the window color
HBRUSH hBrush = CreateSolidBrush (GetSysColor (COLOR_WINDOW));
RECT rect;
// add one to right and bottom, FillRect doesnt include the right and bottom edges
SetRect (&rect, 0, 0, iWidthLP + 1, iHeightLP + 1);
// NOTE: im doing this cause it starts out as all black
FillRect (hMemPrnDC, &rect, hBrush);
// delete object
DeleteBrush (hBrush);
//
// do all my MoveToEx, LineTo, Ellipse, Arc, TextOut,
// SetPixel, etc calls on hMemPrnDC here
//
// copy all the memory DC drawing data to the printer DC
BitBlt (hPrnDC, 0, 0, iWidthLP, iHeightLP, hMemPrnDC, 0, 0, SRCCOPY);
// select old bitmap, and clean up objects
SelectBitmap (hMemPrnDC, hOldBitmap);
DeleteBitmap (hBitmap);
DeleteDC (hMemPrnDC);
hMemPrnDC = NULL;
UPDATE (Sept 5):
here is a link to a PDF print where I draw straight to the printer DC:
hPrnDC.pdf
and here is the same but I draw to the memory DC then BitBlt it to the printer DC:
hMemPrnDC.pdf
now, I did enable my recursive flood fill function on the second, to show an example of what we are trying to achieve, it does the same without it, so that is not an issue
as you can see, the bottom and right edge are cut off, I'm also concerned about the differences in font & line weight between the two, but not as much as the sizing mismatch
NOTE: the filename printed at the top doesn't go through the memory DC, that is always drawn straight to the printer DC
I found a solution to my problem, more of a work-around, but it achieved the desired results...
I only used the memory DC as a go between on the items that needed the recursive flood fill (GetPixel and SetPixel), so I draw them first to the memory DC, copy it all over to the printer DC and then draw everything else straight to the printer DC, seems to work just fine
thanks for the help!

How can i copy the visual content of a window and put it on a new window in win32 c++?

I've read something about GetDIBits or BitBlt but i do not understand them.
That could be because i don't understand how Windows actually handles graphics on windows. It would be perfect if someone could refer me to a page where i could learn about these things! :)
I solved the problem using this code in the windows WM_PAINT. It now shows the exact same content as the target window.
PAINTSTRUCT ps;
HDC hdc = BeginPaint(MainWindow, &ps);
HDC TargetDC = GetDC(TargetWindow);
RECT rect;
GetWindowRect(TargetWindow, &rect);
BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,TargetDC,0,0,SRCCOPY);
EndPaint(MainWindow, &ps);
You might have some luck with sending the window a WM_PRINTCLIENT message. This may not work well for windows that use DirectX or OpenGL.
You may have some issues using WM_PRINTCLIENT on systems that have Aero enabled (i.e. when the DWM is active). If the system DOES have DWM active then it may offer ways of getting at the window backing store but I have not looked into doing that in any great depth before.
What you want is to:
Get a HWND to the window of which you want the pixels.
Create a memory DC of the correct size (check this out).
Send a WM_PRINTCLIENT or WM_PAINT to the window whilst supplying your memory DC (not all controls/windows implement this though)
Copy the contents of your memory DC to screen
Alternatively for step 3 you can use the DWM or get hacky using the clipboard:
void CopyWndToClipboard(CWnd *pWnd)
{
CBitmap bitmap;
CClientDC dc(pWnd);
CDC memDC;
CRect rect;
memDC.CreateCompatibleDC(&dc);
pWnd->GetWindowRect(rect);
bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height());
CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);
pWnd->OpenClipboard() ;
EmptyClipboard() ;
SetClipboardData(CF_BITMAP, bitmap.GetSafeHandle()) ;
CloseClipboard() ;
memDC.SelectObject(pOldBitmap);
bitmap.Detach();
}