Save the screenshot of an application into a bitmap - windows

I am working on a problem, where in I am trying to save the screenshot of a window(including the title bar and borders) to a PNG file. For certain applications like Google Chrome and Visual Studio, I am not able to get the complete window's image that we get with Alt + PrintScreen.
The issues are:
For Google Chrome, I am not getting the Minimize, Maximize and Close buttons
For Visual Studio, I am getting only certain parts and missing Solution Explorer and Output windows.
I have made sure the handle I use is the root window's handle
Below is the code I use to get the BitMap:
hdc = GetDCEx(hwnd, 0, DCX_WINDOW);
hDest = CreateCompatibleDC (hdc);
GetWindowRect (hwnd, &rt);
hBitmap = CreateCompatibleBitmap (hdc, rt.right - rt.left, rt.bottom - rt.top);
SelectObject(hDest, hBitmap);
BitBlt( hDest, 0, 0, rt.right - rt.left, rt.bottom - rt.top, hdc, 0, 0, SRCCOPY);
Thanks,
Raaja

Related

Cant add bmp file to picture control

I'm trying to add a bmp picture in picture controle in my dialog based app.
So basically I have added picture control in dialog, and I have changed picture control type from frame to bitmap. Picture control ID is IDC_STATIC
After that I added this code in header:
CStatic* m_picture;
In project file under OnInitDialog I added this:
m_picture = (CStatic *)GetDlgItem(IDC_STATIC);
HITMAP hb = (HBITMAP)::LoadImage(NULL, L"C:\1.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_picture->ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE);
m_picture->SetBitmap(hb);
I don't get any errors, however the app doesn't work, it doesn't display anything...
Am I missing something?
I think Your Path is not relevant
TO add Image to a Picture Control
// Declare CStatic Object
CStatic aDummyImageName;
//On InitFunction
BOOL YourClassName::OnInitDialog()
{
aDummyImageName= (CStatic*)GetDlgItem(ID of Your Picture Control);
HBITMAP dateImage = (HBITMAP)LoadImage(NULL, L"Path of the Image", IMAGE_BITMAP, 225, 170, LR_LOADFROMFILE);
aDummyImageName->SetBitmap(dateImage);
return TRUE;
}
Try This, It Will Work
IDC_STATIC is used for everything that doesn't change. The program can't find it with that. But once you fix that you may have MY problem, which is that Visual studio keeps revising my picture control in *.rc to no longer be "static", and then it won't build. :(

Deactivating desktop background when a pop up is shown to user

I have a win32 application that runs full screen when started. The application has some button which invoke pop up dialogs.
Is there a way to make the entire desktop (except the pop up) go transparent black unless the pop up is dismissed by the user? what I am talking of is similar to windows 7 UAC pop ups and the background it causes.
Is it possible to do similar stuff for a full screened window app?
It is possible do this…sort of. Perhaps I should say, you can simulate this effect. It won't actually be like the UAC dialog, as the user will still be able to interact with other running applications. There is no such concept as "system modal" available to applications. That's by design, of course. But you can certainly show a "light box" that dims out the rest of the desktop and forces focus on your app's dialog box.
The way I would do it is to create a giant layered window that sits on top of all other windows and covers the entire screen, fill it with black, and set the opacity as desired. Then, before you show a modal dialog (either by calling the MessageBox function or using the DialogBox function to show one of your own custom dialogs), display your light box window. Finally, after the user dismisses the modal dialog, you will destroy the light box window.
Here's some sample code. Error checking is omitted for brevity. So is other good style, like wrapping this mess up in one or more classes.
INT_PTR ShowLightBoxedDialog(HINSTANCE hInstance,
LPCTSTR pDlgTemplate,
HWND hwndParent,
DLGPROC pDlgProc,
BYTE opacityLevel)
{
const TCHAR szLightBoxClass[] = TEXT("LightBoxWndClass");
// Register the light box window class.
static bool lightBoxRegistered = false;
if (!lightBoxRegistered)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(wcex);
wcex.style = CS_NOCLOSE | CS_SAVEBITS;
wcex.lpfnWndProc = LightBoxWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hIconSm = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szLightBoxClass;
RegisterClassEx(&wcex);
lightBoxRegistered = true;
}
// Create and display the light box window.
HWND hwndLightBox = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_LAYERED,
szLightBoxClass,
NULL,
WS_POPUPWINDOW,
0, 0, 0, 0,
hwndParent,
NULL,
hInstance,
NULL);
SetLayeredWindowAttributes(hwndLightBox, 0, opacityLevel, LWA_ALPHA);
SetWindowPos(hwndLightBox,
HWND_TOP,
GetSystemMetrics(SM_XVIRTUALSCREEN),
GetSystemMetrics(SM_YVIRTUALSCREEN),
GetSystemMetrics(SM_CXVIRTUALSCREEN),
GetSystemMetrics(SM_CYVIRTUALSCREEN),
SWP_SHOWWINDOW);
// Display the modal dialog box (as you normally would).
// NOTE: The dialog box won't appear centered on the screen.
// For that, you will need to write centering code in response
// to the WM_INITDIALOG message in the dialog procedure.
INT_PTR result = DialogBox(hInstance, pDlgTemplate, hwndLightBox, pDlgProc);
//
// For demonstration purposes, I used the following code:
// INT_PTR result = MessageBox(hwndLightBox,
// TEXT("OH NOEZ!\n\nYour system is kaput! Abandon þe all hope."),
// NULL,
// MB_ABORTRETRYIGNORE | MB_ICONERROR);
// Destroy the light box window.
DestroyWindow(hwndLightBox);
// Return the result of the modal dialog box.
return result;
}
You'll notice that basically what I've done is created a wrapper around the DialogBox function, which you use whenever you want a dialog box with a "light box" effect. It takes all of the same parameters (the first 4), and then there's an additional one tacked on the end that allows you to specify the opacity level used for the "light box" effect. Something in the range of 150–200 is probably good. Naturally, you could pick something and hard-code it, but I suffer from severe allergies to hard-coded values. Anyway, it's super easy to call this function from anywhere:
ShowLightBoxedDialog(hInstance, /* your application instance */
MAKEINTRESOURCE(IDD_SAMPLE), /* your dialog template */
hWnd, /* parent window for dialog */
SampleWndProc, /* ptr to dialog procedure */
175); /* light box opacity level */
Because the code takes advantage of how modal dialogs already work in Windows, the user won't be able to interact with any other pieces of your application until they dismiss the dialog box. And because the "light box" window is positioned on top of everything else, it eats all mouse clicks and prevents setting focus to any other application. But it is trivial to work around using something like Alt+Tab.
So this is not a security feature! It is merely a visual effect!
And because it's just a silly visual effect, it's likely to be a frustrating one for your users. I don't actually recommend using it. But now you know how to do it. Wield such power responsibly, etc.

Qt: QPainter + GDI in the same widget?

I'm trying to use the method described here to use a QPainter and GDI calls on the same widget.
Unfortunately this tutorial seem to have been written on an earlier version of Qt and now it does not work.
I set the WA_PaintOnScreen flag and reimplement paintEngine() to return NULL.
Then on the paintEvent() I create a QPainter, use it and then use some GDI calls to paint a bitmap. The GDI calls work fine but the QPainter does nothing. I get the following error on the console:
QPainter::begin: Paint device returned engine == 0, type: 1
Is this simply not supported anymore? how can I do it?
I've also tried creating an additional widget on top of the GDI-painting widget but that didn't go well as well since the top widget appears black and blocks the GDI widget.
I got this working in QT 4.7-beta 2 as follows
In the constructor call setAttribute(Qt::WA_PaintOnScreen,true);
Do NOT reimplement paintEngine() to return NULL;
Use the following code in the paintEvent();
QPainter painter(this);
HDC hdc = painter.paintEngine()->getDC(); // THIS IS THE CRITICAL STEP!
HWND hwnd = winID();
// From this point on it is all regular GDI
QString text("Test GDI Paint");
RECT rect;
GetClientRect(hwnd, &rect);
HBRUSH hbrRed = CreateSolidBrush(RGB(255,0,0));
FillRect(hdc, &rect, hbrRed);
HBRUSH hbrBlue = CreateSolidBrush(RGB(40,40,255));
HPEN bpenGreen = CreatePen(PS_SOLID, 4, RGB(0,255,0));
SelectObject(hdc,bpenGreen);
SelectObject(hdc,hbrBlue);
Ellipse(hdc,10,10,rect.right-20,rect.bottom-20);
SetTextAlign(hdc, TA_CENTER | TA_BASELINE);
TextOutW(hdc, width() / 2, height() / 2, text.utf16(), text.size());
ReleaseDC(hwnd, hdc);
This worked with Qt 4.0 and 4.1, but stopped working in either 4.2 or 4.3, when Trolltech reimplemented the Windows paint engine. In the second edition of the Qt 4 book, we added the sentence:
"For this to work, we must also reimplement QPaintDevice::paintEngine() to return a null pointer and set the Qt::WA_PaintOnScreen attribute in the widget's constructor."
I haven't tested it using later versions of Qt (I'm no longer at Trolltech/Nokia and have no Windows machine) but I hope it will still work.

Capturing a Window that is hidden or minimized

I followed this tutorial (there's a bit more than what's listed here because in my code I get a window via mouse click) for grabbing a window as a bitmap and then rendering that bitmap in a different window.
My question:
When that window is minimized or hidden (SW_HIDE) my screen capture doesn't work, so is it possible to capture a window when it is minimized or hidden?
The PrintWindow api works well, I use it for capturing thumbnails for hidden windows. Despite the name, it is different than WM_PRINT and WM_PRINTCLIENT, it works with pretty much every window except for Direct X / WPF windows.
I added some code (C#) but after reviewing how I used the code, I realized that the window isn't actually hidden when I capture its bitmap, its just off screen so this may not work for your case. Could you show the window off screen, do a print and then hide it again?
public static Bitmap PrintWindow(IntPtr hwnd)
{
RECT rc;
WinUserApi.GetWindowRect(hwnd, out rc);
Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
bool succeeded = WinUserApi.PrintWindow(hwnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
if (!succeeded)
{
gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size));
}
IntPtr hRgn = WinGdiApi.CreateRectRgn(0, 0, 0, 0);
WinUserApi.GetWindowRgn(hwnd, hRgn);
Region region = Region.FromHrgn(hRgn);
if (!region.IsEmpty(gfxBmp))
{
gfxBmp.ExcludeClip(region);
gfxBmp.Clear(Color.Transparent);
}
gfxBmp.Dispose();
return bmp;
}
There are WM_PRINT and WM_PRINTCLIENT messages you can send to the window, which cause its contents to be rendered into the HDC of your choice.
However, these aren't perfect: while the standard Win32 controls handle these correctly, any custom controls in the app might not.
I am trying to get the bitmap of partially hidden controls.
I used code before that did the drawing, but included windows overlapping it. So.. maybe you want to try this.
The WM_PRINTCLIENT should (in my understanding) redraw all inside the control, even if it is not really visible.
const int WM_PRINT = 0x317, WM_PRINTCLIENT = 0x318, PRF_CLIENT = 4,
PRF_CHILDREN = 0x10, PRF_NON_CLIENT = 2,
COMBINED_PRINTFLAGS = PRF_CLIENT | PRF_CHILDREN | PRF_NON_CLIENT;
SendMessage(handle, WM_PRINTCLIENT, (int)hdc, COMBINED_PRINTFLAGS);
//GDIStuff.BitBlt(hdc, 0, 0, width, height, hdcControl, 0, 0, (int)GDIStuff.TernaryRasterOperations.SRCCOPY);
The before code is commented out now. It is based on the code found here: Pocket PC: Draw control to bitmap (accepted answer). It is basically the same as Tim Robinson suggests in this thread.
Also, have a look here
http://www.tcx.be/blog/2004/paint-control-onto-graphics/

StretchBlt fails when printing

I have a chart (in bitmap format) that I'm trying to render to a printer using StretchBlt. When drawing to the screen, StretchBlt works fine. When drawing to a CutePDF printer, it returns 0, sets the last error to ERROR_INVALID_HANDLE, and works anyway. When drawing to a PDF995 printer or a physical HP printer, it returns 0, sets the last error to ERROR_INVALID_HANDLE, and fails to draw anything.
What would cause StretchBlt to fail for certain devices? I've verified that the source bitmap is a DIB and that the destination supports StretchBlt by calling GetDeviceCaps.
Here's my code, in case it's relevant: (It's written in C++Builder, so it uses Delphi's VCL; TCanvas wraps an HDC, and TBitmap wraps an HBITMAP. VCL provides its own StretchDraw function which does not support HALFTONE; I'm getting the same problems with it.)
void PrettyStretchDraw(TCanvas *dest, const TRect& rect, TGraphic *source)
{
if (dynamic_cast<Graphics::TBitmap*>(source) && !source->Transparent) {
POINT pt;
GetBrushOrgEx(dest->Handle, &pt);
SetStretchBltMode(dest->Handle, HALFTONE);
SetBrushOrgEx(dest->Handle, pt.x, pt.y, NULL);
StretchBlt(
dest->Handle,
rect.Left,
rect.Top,
rect.Width(),
rect.Height(),
dynamic_cast<Graphics::TBitmap*>(source)->Canvas->Handle,
0,
0,
source->Width,
source->Height,
SRCCOPY);
} else {
DrawItSomeOtherWay(dest, rect, source);
}
}
StretchBlt is broken on some printer drivers (PDF995 is notable example).
I once encontered this error happening on Windows 2003 Server only (it worked on XP).
Try to reproduce the problem on other OS, and it it does not, consider it OS specific and use StretchDIBits instead on this OS.

Resources