0

I select displays in multiple display environments and produce captured programs.

And try to draw a cursor by selecting dc among multiple displays.

I draw cursors with bitblt bitmap images and it works well.

HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);

But When I select from createDC multuple display value,

DISPLAY_DEVICEW info = { 0 };
info.cb = sizeof(DISPLAY_DEVICEW);
EnumDisplayDevicesW(NULL, 0, &info, EDD_GET_DEVICE_INTERFACE_NAME); 
HDCC = CreateDC(info.DeviceName, NULL, NULL, NULL);

I am working hard to get other display images. But there is no drawing cursor. (Other forms of cursor are not drawn, only text cursor is drawn)

This is my code.

const int d_count = GetSystemMetrics(SM_CMONITORS);  //I have 3 display and count is 3.
HDC hCaptureDC;
HDC HDCC;
HBITMAP hBitmap;
HGDIOBJ hOld;
BYTE *src;


bool GetMouse() {
     CURSORINFO cursor = { sizeof(cursor) };
     ::GetCursorInfo(&cursor);

     ICONINFOEXW info = { sizeof(info) };
     ::GetIconInfoExW(cursor.hCursor, &info);

     BITMAP bmpCursor = { 0 };
     GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);

     POINT point;
     GetCursorPos(&point);

     bool res = DrawIconEx(hCaptureDC, point.x, point.y, cursor.hCursor, bmpCursor.bmWidth, bmpCursor.bmHeight, 0, NULL, DI_NORMAL);
     return res;
}

void screencap(){
    BITMAPINFO MyBMInfo;
    BITMAPINFOHEADER bmpInfoHeader;
    HWND m_hWndCopy= GetDesktopWindow();
    GetClientRect(m_hWndCopy, &ImageRect);  
    const int nWidth = ImageRect.right - ImageRect.left; 
    const int nHeight = ImageRect.bottom - ImageRect.top;

    MyBMInfo = { 0 };
    MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

    bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
    bmpInfoHeader.biWidth = nWidth;
    bmpInfoHeader.biHeight = nHeight;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = 32;

    b_size = ((nWidth * bmpInfoHeader.biBitCount + 31) / 32) * 4 * nHeight;

     //HDCC = CreateDC((L"Display"), NULL, NULL, NULL);   //It's good.
    DISPLAY_DEVICEW info = { 0 };
    info.cb = sizeof(DISPLAY_DEVICEW);
    EnumDisplayDevicesW(NULL, 0, &info, EDD_GET_DEVICE_INTERFACE_NAME); 
    HDCC = CreateDC(info.DeviceName, NULL, NULL, NULL);   // It draws only text cursor.

    hCaptureDC = CreateCompatibleDC(HDCC);
    hBitmap = CreateCompatibleBitmap(HDCC, nWidth, nHeight);
    hOld = SelectObject(hCaptureDC, hBitmap);

    BitBlt(hCaptureDC, 0, 0, nWidth, nHeight, HDCC, 0, 0, SRCCOPY);

    GetMouse();

    SelectObject(hCaptureDC, hOld);

    src = (BYTE*)malloc(b_size);
    if (GetDIBits(hCaptureDC, hBitmap, 0, nHeight, src, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS)) {
        if (RGBSaveBMP(src) == true) 
        free(src);
    }  
}

I'm using windows 10.

How can I solved?

Any links, idea, Thanks.

ADD

It does not draw cursor....(except text cursor.)

HDCC = CreateDC(TEXT("\\\\.\\Display1"), NULL, NULL, NULL);

HDCC = CreateDC(TEXT("\\.\Display1"), NULL, NULL, NULL);

It draws cursor..

HDCC = CreateDC(TEXT("Display"), NULL, NULL, NULL);

HDCC = CreateDC(TEXT("Display"), NULL, NULL, NULL);

SOLVED:

Now, I changed my algorithm.

CreateDC(L"Display", NULL, NULL, NULL) create DC for all monitors, so what is your problem? – user2120666 Apr 22 at 15:37

This comment is very helpful but It was not kind. (Or I was stupid.) :(

HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);

HDCC has "All Virtual Screens" DC.

When I selected the monitor I needed, and accordingly selected and used the area to capture on the virtual screen.

HDC hCaptureDC = CreateCompatibleDC(HDCC);  
HBITMAP hBitmap = CreateCompatibleBitmap(HDCC, nWidth, nHeight);
HDC HDCC = CreateDC((L"Display"), NULL, NULL, NULL);
DEVMODE dev;

std::string str = "\\\\.\\Display" + std::to_string(select);
std::wstring temp;
temp.assign(str.begin(), str.end());

EnumDisplaySettingsW(temp.c_str(), ENUM_CURRENT_SETTINGS, &dev);
printf("Display%d : (%d * %d) (%d, %d)\n", select, dev.dmPelsWidth, dev.dmPelsHeight, dev.dmPosition.x, dev.dmPosition.y);

nWidth = dev.dmPelsWidth;
nHeight = dev.dmPelsHeight;
nposx = dev.dmPosition.x;
nposy = dev.dmPosition.y;

hOld = SelectObject(hCaptureDC, hBitmap);
BitBlt(hCaptureDC, 0, 0, nWidth, nHeight, HDCC, nposx, nposy, SRCCOPY);
int colorcheck = GetSystemMetrics(SM_SAMEDISPLAYFORMAT);

CURSORINFO cursor = { sizeof(cursor) };
bool check = ::GetCursorInfo(&cursor);
bool check2 = ::GetCursorInfo(&cursor);
int count = ShowCursor(TRUE);

info = { sizeof(info) };
::GetIconInfoExW(cursor.hCursor, &info);

GetCursorPos(&point);

if (point.x > nWidth) {
    point.x = point.x - nWidth;
}
else if (point.x < 0) {
    point.x = nWidth + point.x;
}
if (point.y > nHeight) {
    point.y = point.y - nHeight;
}
else if (point.y < 0) {
    point.y = nHeight + point.y;
}
cursor.ptScreenPos.x = point.x;
cursor.ptScreenPos.y = point.y;

bool res = ::DrawIconEx(hCaptureDC, point.x, point.y, cursor.hCursor, 0, 0, 0, NULL, DI_NORMAL);


BYTE* src = (BYTE*)malloc(b_size);
GetDIBits(hCaptureDC, hBitmap, 0, nHeight, src, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS)

Thanks for the comment!

Birds
  • 65
  • 2
  • 13
  • 1
    Please show a [mcve]. And since you are looking for help, you need to make it easy for us to help you. Properly formatting the code goes a long way. – IInspectable Apr 22 '19 at 13:40
  • CreateDC(L"Display", NULL, NULL, NULL) create DC for all monitors, so what is your problem? – user2120666 Apr 22 '19 at 15:37
  • @IInspectable I edited my question. I am sorry if U do not understand. I was very tired. :) – Birds Apr 23 '19 at 00:09
  • @user2120666 It worked well on a single display. However, when capturing the screen with multiple displays and drawing the cursor, it is not drawn. – Birds Apr 23 '19 at 00:13
  • Can you publish two pictures for comparison? – Strive Sun Apr 23 '19 at 08:15
  • @Strive Sun - MSFT I Add pictures... thanks. – Birds Apr 23 '19 at 08:47
  • @Birds hello, Birds, your problem hasn't been solved yet, has it? You seem to have tried my method, but it doesn't work. – Strive Sun Apr 24 '19 at 02:02
  • @StriveSun-MSFT Sun - MSFT Yes. I did. So I change method. Now, I get DC of virtual screen and set BitBlt capture area individually based on monitor index and I use it. The explanation of my method will update the answer later – Birds Apr 24 '19 at 04:00

2 Answers2

0

Following MSDN to get EnumDisplayMonitor may solve your problem.

Use EnumDisplayMonitors to get the device name and pass it to CreateDC.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • I can get a second display image. However, you can not draw the cursor. Is this answer relevant? – Birds Apr 23 '19 at 07:43
  • @Birds Because I don't have multiple monitors to test, but I get this conclusion by consulting the data. You can try it. I hope it can help you. – Strive Sun Apr 23 '19 at 07:46
0

Your call GetClientRect(m_hWndCopy, &ImageRect); is wrong.

From documentation:

The rectangle of the desktop window returned by GetWindowRect or GetClientRect is always equal to the rectangle of the primary monitor, for compatibility with existing applications.

So you are capturing only primary display.

user2120666
  • 579
  • 1
  • 4
  • 16