6

i am writing a screen capture application in Qt4 with c++. I have a problem when tuning on dual screens. I am unable to get an image with the second screen. I tried a c# application and that will grab all the desktops in one image and i could extract from there each screen desktop image. Here is the c# code

    using System;
using System.Drawing;
using System.Runtime.InteropServices;

public class TestGrab
{
  [STAThread]
  static void Main(string[] args)
  {
    IntPtr hDC = WindowsNative.GetDC(WindowsNative.GetDesktopWindow());
    IntPtr hBitmap = WindowsNative.GetCurrentObject(hDC,
    WindowsNative.OBJ_BITMAP);
    System.Drawing.Bitmap imageDesktop = System.Drawing.Image.FromHbitmap(
    hBitmap);
    imageDesktop.Save(@"c:\zzzzdesktop.png");
  }
}

public class WindowsNative
{
  [DllImport("user32.dll")]
  public static extern IntPtr GetDesktopWindow();

  [DllImport("user32.dll")]
  public static extern IntPtr GetDC(IntPtr ptr);

  public const int OBJ_BITMAP = 7;
  [DllImport("gdi32.dll")]
  public static extern IntPtr GetCurrentObject(IntPtr hdc, uint
  uiObjectType);
}

The Qt code is smaller,also i tested if the native windows handle to the desktop is different from the Qt desktop0>winId() but them are equal

QPixmap CaptureWinDesktop()
{
    WId desktop=GetDesktopWindow();
    WId desktop2=QApplication::desktop()->winId();
    if(desktop!=desktop2)
    {
        qDebug("sunt fdiferite WId");
    }
     QPixmap entireDesktop= QPixmap::grabWindow(desktop);
     return entireDesktop;
}

I am not sure if this is a bug in Qt or is a feature, using the same window handle it retries only the first desktop when in fact the desktop it is relay composed from the 2 screens . One idea is to use native windows calls and save the image in a temp file and load a QPixmap from there, but that is not simple to save a HBITMAP in a file in c++ without MFC. Conclusion: what do you think is that a bug in Qt? any idea how to work around it(no MFC )

simion314
  • 1,394
  • 16
  • 29
  • Also i found an example using GDI http://www.experts-exchange.com/Microsoft/Development/Q_26484815.html ,look at the bottom, the numbers are hard coded, so you have to get the dimensions and modify the code – simion314 Oct 19 '10 at 14:18

4 Answers4

4

you can count screens with QDesktopWidget::screenCount() (Qt 4.6) and then travel through all screens and do QPixmap::grabWindow(...)

About "desktop composed from 2 screens". It all depends if 2 screen is virtual (all screens treated as one screen) or not.

@Frerich Raabe: it works on Windows 7 as I'm using similar code to perform screen grab.

Kamil Klimek
  • 12,884
  • 2
  • 43
  • 58
  • :grabWindow(...) will return for me the first screen even if i use the second screen. Are you sure it works in dual monitors? – simion314 Oct 19 '10 at 14:13
  • I was recently implementing grab screen functionality, and yes it was working fine. What verrsion of Qt you're using? – Kamil Klimek Oct 19 '10 at 16:48
  • i am using 4.6.3 on Windows XP sp3, i have setup a dual monitors and i always get only the first scree, and i tried all possibilities, i relay do not like to use win APIDS – simion314 Oct 19 '10 at 18:43
  • I installed the atest SDK and i have the same problem. – simion314 Oct 19 '10 at 22:59
  • Oh, I didn't test it yet on Windows XP as we're not sure if we will support it. I wrote that it works on Windows 7 (vista also). If I'll have posibility I'll test it on Windows XP – Kamil Klimek Oct 20 '10 at 05:27
  • I get this result on my machine : Desktop Id 0x10014 geometry QRect(0,0 3200x1080) screen1 Id 0x10014 geometry QRect(0,0 3200x1080) Desktop Id 0x10014 geometry QRect(0,0 3200x1080) So i think is a bug – simion314 Oct 21 '10 at 11:01
3

I recently noticed the same issue.

I eventually decided to drop Qt for taking screenshots. Another situation in whic Qt breaks is when using the Aero theme of Windows Vista or Windows 7. This theme apparently renders all data into a background buffer, so all screenshots taken by Qt are all black.

Instead of using Qt I can recommend using the ScreenShooter class as described at http://www.apriorit.com/our-experience/articles/9-sd-articles/193-multi-monitor-screenshot

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • Thx, this could save me figting with all the HDC,RECT HBITMAP and other complex structs – simion314 Oct 19 '10 at 14:09
  • If your application is open source i would like to see the code, it seems to me that the screenshot app you linked uses MFC atlimage.h – simion314 Oct 21 '10 at 11:47
2

With a virtual desktop, the QPixmap::grabWindow method seems to return a screenshot with the size of the primary screen. Passing in the dimensions of the full virtual desktop returns a screenshot of both monitors;

  QDesktopWidget *desktop = QApplication::desktop();
  QPixmap screenshot = QPixmap::grabWindow(desktop->winId(), 0, 0, desktop->width(), desktop->height());

Yet to test this behaviour on a Unix / Mac box, but it works under Windows 7.

sixones
  • 1,953
  • 4
  • 21
  • 25
0

In a multi-monitor setup on Windows, the monitors are usually joined into a virtual desktop. I say "usually" because I'm not entirely sure what happens on all the Windows versions from XP SP0 (October 25, 2001) to Win8 SP0 (October 26, 2012). But, as a virtual desktop, that means that screen(x) will always return the same widget; from what I've seen this is the one and only QDesktopWidget itself. However, screenGeometry(x) will return different values for each enumerated monitor.

You can grab the second screen by using the result of screenGeometry(x) as the parameters to QPixmap::grabWindow; ie:

QDesktopWidget* desktop = QApplication::desktop();
WId wid = desktop->winId();
QRect geo = desktop->screenGeometry(indexOfTheMonitorYouWant);
QPixmap cap = QPixmap::grabWindow(wid, geo.left(), geo.top(), geo.width(), geo.height());

This is working for me right now, and I'm about to hand the build off to my QA team.

AndrewS
  • 8,196
  • 5
  • 39
  • 53