none
problem capturing desktop and mouse icon

    Question

  • I want to capture desktop with the mouse cursor showing.   I am able to successfully do this if I capture the entire "virtual desktop".  However, when I try the same code with a hDC to a specific display the mouse cursor isn't drawn on the bitmap.

    This code works for the entire desktop:

    HWND hDesktopWnd = GetDesktopWindow();
    HDC hDesktopDC = GetDC(hDesktopWnd);
    
    HDC hDesktopCompatibleDC = CreateCompatibleDC(hDesktopDC);
    HBITMAP	hCompatibableBitmap = CreateCompatibleBitmap(hDesktopDC, g_configuration.OutputWidth, g_configuration.OutputHeight);
    HBITMAP hOldBitmap = (HBITMAP) SelectObject(hDesktopCompatibleDC, hCompatibableBitmap);
    
    BitBlt(hDesktopCompatibleDC, 0, 0, nScreenWidth, nScreenHeight, hDesktopDC, 0, 0, SRCCOPY);
    
    CURSORINFO cursor;
    memset(&cursor, 0, sizeof(CURSORINFO));
    cursor.cbSize = sizeof(CURSORINFO);
    
    GetCursorInfo(&cursor);
    
    HICON hMouseIcon = CopyIcon(cursor.hCursor);
    ICONINFO iconInfo;
    memset(&iconInfo, 0, sizeof(ICONINFO));
    
    if (TRUE == GetIconInfo(hMouseIcon, &iconInfo))
        DrawIcon(hDesktopCompatibleDC, cursor.ptScreenPos.x, cursor.ptScreenPos.y, hMouseIcon))    
    


    To capture the desktop of a given monitor,  I replace  hDesktopDC = GetDC(hDesktopWnd) with

    hDesktopDC = CreateDC(NULL, TEXT("\\\\.\\DISPLAY1"), NULL, NULL)

    The desktop is still captured but no mouse cursor is drawn.  The mouse methods are not returning errors (I removed my handlers for errors to make the code example clear).  So it "appears" to succeed even though there is no mouse cursor.  (the mouse is on the captured display at the time of capture).

    Thnx

    Matt

    Wednesday, November 21, 2012 8:14 PM

Answers

  • I resolved my problem.   The resolution is to combine capturing the entire desktop (with HDC hDesktopDC (hDesktopWnd); method call) and using information provided in the EnumDisplayMonitors callback to extract just the monitor I want and draw the cursor as needed.  Since cursor position is based on the entire virtual desktop (all monitors combined) with the primary monitor at 0,0, I had to calculate if and where the cursor is drawn.

    This code below is my solution (its assimulated from several methods, I think its all correct but it's possible there's something amiss.  Likewise, for clarity, I have removed all error handling and resource releases)

    HWND hDesktopWnd = GetDesktopWindow(); HDC hDesktopDC = GetDC(hDesktopWnd); // in my solution, these values came from an external source int someOutputWidth; int someOutputHeight; HDC hDesktopCompatibleDC = CreateCompatibleDC(hDesktopDC); HBITMAP hCompatibableBitmap = CreateCompatibleBitmap(hDesktopDC, someOutputWidth, someOutputHeight); HBITMAP hOldBitmap = (HBITMAP) SelectObject(hDesktopCompatibleDC, hCompatibableBitmap); // rMonitor is the RECT passed in 3rd parameter of the EnumDisplayMonitors callback method int startingPointX = rMonitor.left; int startingPointY = rMonitor.top; int monitorWidth = abs(abs(rMonitor.left) - rMonitor.right); int monitorHeight = abs(abs(rMonitor.top) - rMonitor.bottom); SetStretchBltMode(hDesktopCompatibleDC, COLORONCOLOR); StretchBlt(hDesktopCompatibleDC, 0, 0, someOutputWidth, someOutputHeight, hDesktopDC, startingPointX, startingPointY, monitorWidth, monitorHeight, SRCCOPY); CURSORINFO cursor; memset(&cursor, 0, sizeof(CURSORINFO)); cursor.cbSize = sizeof(CURSORINFO); GetCursorInfo(&cursor); HICON hMouseIcon = CopyIcon(cursor.hCursor); ICONINFO iconInfo; memset(&iconInfo, 0, sizeof(ICONINFO)); GetIconInfo(hMouseIcon, &iconInfo); // cursor screen position is the coordinates based on how the monitor layout is configured // and is relative to top left cornor of the primary monitor (which is 0,0). Thus a monitor // to the left will have negative cursor values. also we have a bitmap that was extracted // from part of the virtual layout whose coordinates are positive numbers with top left being 0,0. // so we have to figure out a) does the mouse cursor need to drawn on the image (since its possible // its on a different monitor and b) where to put it. int x = cursor.ptScreenPos.x; int y = cursor.ptScreenPos.y; // at this point, cursor position will fit in the range of monitor rectangle values // so we can test for "in-range" if ((x >= rMonitor.left && x <= rMonitor.right) && (y >= rMonitor.top && y <= rMonitor.bottom)) { // as stated aboce, the bitmap top left is 0,0 but when the cursor is at the top left monitor, cursor position is "anything". // it could be 0,0 or 0,-1920, or -1080,0 all depending on how the monitors are configured. // now, we convert that to absolute position on the bitmap x = nWidth - abs(x - rMonitor.right); y = nHeight - abs(y - rMonitor.bottom); DrawIcon(hBitmapDC, x, y, hMouseIcon)); }


    I hope this helps anyone else looking to solve similar challenges.

    Matt



    • Marked as answer by tatman blue Tuesday, November 27, 2012 5:56 PM
    • Edited by tatman blue Monday, December 03, 2012 10:07 PM
    Tuesday, November 27, 2012 5:30 PM

All replies

  • I resolved my problem.   The resolution is to combine capturing the entire desktop (with HDC hDesktopDC (hDesktopWnd); method call) and using information provided in the EnumDisplayMonitors callback to extract just the monitor I want and draw the cursor as needed.  Since cursor position is based on the entire virtual desktop (all monitors combined) with the primary monitor at 0,0, I had to calculate if and where the cursor is drawn.

    This code below is my solution (its assimulated from several methods, I think its all correct but it's possible there's something amiss.  Likewise, for clarity, I have removed all error handling and resource releases)

    HWND hDesktopWnd = GetDesktopWindow(); HDC hDesktopDC = GetDC(hDesktopWnd); // in my solution, these values came from an external source int someOutputWidth; int someOutputHeight; HDC hDesktopCompatibleDC = CreateCompatibleDC(hDesktopDC); HBITMAP hCompatibableBitmap = CreateCompatibleBitmap(hDesktopDC, someOutputWidth, someOutputHeight); HBITMAP hOldBitmap = (HBITMAP) SelectObject(hDesktopCompatibleDC, hCompatibableBitmap); // rMonitor is the RECT passed in 3rd parameter of the EnumDisplayMonitors callback method int startingPointX = rMonitor.left; int startingPointY = rMonitor.top; int monitorWidth = abs(abs(rMonitor.left) - rMonitor.right); int monitorHeight = abs(abs(rMonitor.top) - rMonitor.bottom); SetStretchBltMode(hDesktopCompatibleDC, COLORONCOLOR); StretchBlt(hDesktopCompatibleDC, 0, 0, someOutputWidth, someOutputHeight, hDesktopDC, startingPointX, startingPointY, monitorWidth, monitorHeight, SRCCOPY); CURSORINFO cursor; memset(&cursor, 0, sizeof(CURSORINFO)); cursor.cbSize = sizeof(CURSORINFO); GetCursorInfo(&cursor); HICON hMouseIcon = CopyIcon(cursor.hCursor); ICONINFO iconInfo; memset(&iconInfo, 0, sizeof(ICONINFO)); GetIconInfo(hMouseIcon, &iconInfo); // cursor screen position is the coordinates based on how the monitor layout is configured // and is relative to top left cornor of the primary monitor (which is 0,0). Thus a monitor // to the left will have negative cursor values. also we have a bitmap that was extracted // from part of the virtual layout whose coordinates are positive numbers with top left being 0,0. // so we have to figure out a) does the mouse cursor need to drawn on the image (since its possible // its on a different monitor and b) where to put it. int x = cursor.ptScreenPos.x; int y = cursor.ptScreenPos.y; // at this point, cursor position will fit in the range of monitor rectangle values // so we can test for "in-range" if ((x >= rMonitor.left && x <= rMonitor.right) && (y >= rMonitor.top && y <= rMonitor.bottom)) { // as stated aboce, the bitmap top left is 0,0 but when the cursor is at the top left monitor, cursor position is "anything". // it could be 0,0 or 0,-1920, or -1080,0 all depending on how the monitors are configured. // now, we convert that to absolute position on the bitmap x = nWidth - abs(x - rMonitor.right); y = nHeight - abs(y - rMonitor.bottom); DrawIcon(hBitmapDC, x, y, hMouseIcon)); }


    I hope this helps anyone else looking to solve similar challenges.

    Matt



    • Marked as answer by tatman blue Tuesday, November 27, 2012 5:56 PM
    • Edited by tatman blue Monday, December 03, 2012 10:07 PM
    Tuesday, November 27, 2012 5:30 PM
  • In this code, can you tell me what nWidth, nHeight, and hBitmapDC are?
    Tuesday, February 05, 2013 4:22 PM
  • My apologizes, I joined two methods in an attempt to simplify the answer and had some typos:

    nHeight, nWidth are height and width of the monitor (aka monitorWidth monitorHeight at the top of the code sample)

    hBitmapDC is hDesktopCompatibleDC 

    Matt


    • Edited by tatman blue Thursday, February 07, 2013 3:35 PM
    Thursday, February 07, 2013 3:34 PM