绘制光标多重显示(只绘制文字图标)GDI

Draw cursor multiple display (only draw text icon) GDI

我select在多种显示环境中显示并生成捕获的程序。

并尝试通过 select在多个显示器之间 dc 来绘制光标。

我用 bitblt 位图图像绘制光标,效果很好。

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

但是当我select从createDC multiple显示值时,

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);

我正在努力获取其他显示图像。但是没有绘图光标。 (其他形式的光标不画,只画文字光标)

这是我的代码。

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);
    }  
}

我正在使用 windows 10.

我该如何解决?

任何链接,想法,谢谢。

添加

不绘制光标....(文本光标除外。)

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

绘制光标..

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

已解决:

现在,我改变了我的算法。

CreateDC(L"Display", NULL, NULL, NULL) 为所有监视器创建DC,那么你的问题是什么? – user2120666 4 月 22 日 15:37

这条评论很有帮助,但不够友善。 (或者我是愚蠢的。):(

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

HDCC 有 "All Virtual Screens" DC。

当我 select 编辑我需要的监视器时,相应地 select 编辑并使用该区域在虚拟屏幕上进行捕获。

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)

感谢评论!

关注MSDN得到EnumDisplayMonitor可能会解决你的问题。

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

你的调用GetClientRect(m_hWndCopy, &ImageRect);是错误的。

来自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.

所以您只捕获主要显示。