Winapi: скриншот не отображается в окне - PullRequest
0 голосов
/ 21 октября 2018

Я новичок в программировании графического интерфейса для Windows и столкнулся с некоторыми проблемами (с использованием Visual Studio 2017).

У меня есть клиентское и серверное приложение, клиент в основном делает снимки рабочего стола и отправляет его на сервер, которыйзатем отображает его на экране.Поскольку я решил опубликовать вопрос здесь, я создал один проект, который создает окно (которое используется для отображения скриншотов), делает снимок экрана и отображает его (я пытался использовать как можно меньше кода для воспроизведения проблемы).

Вот код:

// Onefile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define SECURITY_WIN32
#include <Windowsx.h>
#include <WinSock.h>
#include <Windows.h>
#include <WinBase.h>
#include <Stdio.h>
#include <Security.h>
#include <Sddl.h>
#include <Shlwapi.h>
#include <Shlobj.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <Wininet.h>
#include <Urlmon.h>

#pragma comment(lib,"WS2_32")

static BITMAPINFO g_bmpInfo;
static BYTE      *g_pixels = NULL;
HWND hWndClient;
HDC hDcBmpServer;
static const TCHAR *className = TEXT("ControlWindow");
static const TCHAR *titlePattern = TEXT("Desktop");

static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
  case WM_CREATE:
  {
    printf("WndProc: WM_CREATE\n");
    fflush(stdout);
    break;
  }
  case WM_SYSCOMMAND:
  {
    printf("WndProc: WM_SYSCOMMAND\n");
    fflush(stdout);
    return DefWindowProc(hWnd, msg, wParam, lParam);
  }
  case WM_PAINT:
  {
    printf("WndProc: WM_PAINT\n");
    fflush(stdout);

    PAINTSTRUCT ps;
    HDC         hDc = BeginPaint(hWnd, &ps);

    if (hDc == NULL)
    {
      printf("WM_PAINT: BeginPaint FAILED!\n");
      fflush(stdout);
    }

    RECT clientRect;
    if (GetClientRect(hWnd, &clientRect) == 0)
    {
      printf("WM_PAINT: GetClientRect FAILED %d\n", GetLastError());
      fflush(stdout);
    }

    RECT rect;
    HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));

    if (hBrush == NULL)
    {
      printf("%d WM_PAINT: CreateSolidBrush FAILED %d\n", GetLastError());
      fflush(stdout);
    }

    rect.left = 0;
    rect.top = 0;
    rect.right = clientRect.right;
    rect.bottom = clientRect.bottom;

    rect.left = g_bmpInfo.bmiHeader.biWidth;


    if (FillRect(hDc, &rect, hBrush) == 0)
    {
      printf("WM_PAINT: FillRect 1.0 failed!\n");
      fflush(stdout);
    }

    rect.left = 0;
    rect.top = g_bmpInfo.bmiHeader.biHeight;


    if (FillRect(hDc, &rect, hBrush) == 0)
    {
      printf("WM_PAINT: FillRect 2.0 failed!\n");
      fflush(stdout);
    }
    DeleteObject(hBrush);

    if (BitBlt(hDc, 0, 0, g_bmpInfo.bmiHeader.biWidth, g_bmpInfo.bmiHeader.biHeight, hDcBmpServer, 0, 0, SRCCOPY) == 0)
    {
      printf("WM_PAINT: BitBlt failed!%d\n", GetLastError());
      fflush(stdout);
    }
    else
    {
      printf("WM_PAINT: BitBl SUCCESS!\n");
      fflush(stdout);
    }
    EndPaint(hWnd, &ps);
    break;
  }
  case WM_DESTROY:
  {
    PostQuitMessage(0);
    break;
  }
  case WM_ERASEBKGND:
    return TRUE;
  case WM_LBUTTONDOWN:
  case WM_LBUTTONUP:
  case WM_RBUTTONDOWN:
  case WM_RBUTTONUP:
  case WM_MBUTTONDOWN:
  case WM_MBUTTONUP:
  case WM_LBUTTONDBLCLK:
  case WM_RBUTTONDBLCLK:
  case WM_MBUTTONDBLCLK:
  case WM_MOUSEMOVE:
  case WM_MOUSEWHEEL:
  {
    printf("WndProc: Buttons\n");
    fflush(stdout);
    break;
  }
  case WM_CHAR:
  {
    printf("WndProc: WM_char\n");
    fflush(stdout);
    break;
  }
  case WM_KEYDOWN:
  case WM_KEYUP:
  {
    printf("WndProc: KEYUPm\n");
    fflush(stdout);
    switch (wParam)
    {
    case VK_UP:
    case VK_DOWN:
    case VK_RIGHT:
    case VK_LEFT:
    case VK_HOME:
    case VK_END:
    case VK_PRIOR:
    case VK_NEXT:
    case VK_INSERT:
    case VK_RETURN:
    case VK_DELETE:
    case VK_BACK:
      break;
    }
  }
  case WM_GETMINMAXINFO:
  {
    printf("WndProc: WM_GETMINMAXINFO\n");
    fflush(stdout);
    break;
  }
  default:
    return DefWindowProc(hWnd, msg, wParam, lParam);
  }
return 0;
}

//Register class
BOOL CW_Register(WNDPROC lpfnWndProc)
{
  WNDCLASSEX wndClass;
  wndClass.cbSize = sizeof(WNDCLASSEX);
  wndClass.style = CS_DBLCLKS;
  wndClass.lpfnWndProc = lpfnWndProc;
  wndClass.cbClsExtra = 0;
  wndClass.cbWndExtra = 0;
  wndClass.hInstance = NULL;
  wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
  wndClass.lpszMenuName = NULL;
  wndClass.lpszClassName = className;
  wndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  return RegisterClassEx(&wndClass);
}

//Create window which should display pictures
HWND CW_Create()
{
  printf("CW_Create: Creating Windows...\n");
  fflush(stdout);

  hWndClient = CreateWindow(className,
    titlePattern,
    WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX | WS_SYSMENU,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    800,
    600,
    NULL,
    NULL,
    GetModuleHandle(NULL),
    NULL);

  if (hWndClient == NULL)
  {
    printf("CW_Create:  ERROR! CreateWindow failed %d\n", GetLastError());
    fflush(stdout);
    return NULL;
  }

  if (ShowWindow(hWndClient, SW_SHOW) == 0)
  {
    printf("CW_Create: The window was previously hidden\n");
    fflush(stdout);
    return NULL;
  }
  else
  {
    printf("CW_Create: The window was previously shown\n");
    fflush(stdout);
  }
  printf("CW_Create: Exiting...\n");
  return hWndClient;
}


void CreateWindows()
{
  CW_Register(WndProc);
  CW_Create();
}

int main()
{
  CreateWindows();

  memset(&g_bmpInfo, 0, sizeof(g_bmpInfo));

  g_bmpInfo.bmiHeader.biSize = sizeof(g_bmpInfo.bmiHeader);
  g_bmpInfo.bmiHeader.biPlanes = 1;
  g_bmpInfo.bmiHeader.biBitCount = 24;
  g_bmpInfo.bmiHeader.biCompression = BI_RGB;
  g_bmpInfo.bmiHeader.biClrUsed = 0;
  g_bmpInfo.bmiHeader.biSizeImage = 800 * 3 * 600;

  //Client side which takes a picture of screen
  RECT rect;
  HWND hWndDesktop = GetDesktopWindow();
  GetWindowRect(hWndDesktop, &rect);

  HDC     hDc = GetDC(NULL);

  if(hDc == NULL)
  {
    printf("Client: hDc is NULL %d\n", GetLastError());
  }
  HDC     hDcScreen = CreateCompatibleDC(hDc);

  if (hDcScreen == NULL)
  {
    printf("Client: hDcScreen is NULL %d\n", GetLastError());
  }

  HBITMAP hBmpScreen = CreateCompatibleBitmap(hDc, rect.right - rect.left, rect.bottom - rect.top);

  if (hBmpScreen == NULL)
  {
    printf("Client: hBmpScreen is NULL %d\n", GetLastError());
  }

  //Resize the picture to 800x600 dimension
  HBITMAP hBmpScreenResized = CreateCompatibleBitmap(hDc, 800, 600);

  if (hBmpScreenResized == NULL)
  {
    printf("Client: hBmpScreenResized is NULL %d\n", GetLastError());
  }
  HDC     hDcScreenResized = CreateCompatibleDC(hDc);

  if (hDcScreenResized == NULL)
  {
    printf("Client: hDcScreenResized is NULL %d\n", GetLastError());
  }

  SelectObject(hDcScreenResized, hBmpScreenResized);

  SetStretchBltMode(hDcScreenResized, HALFTONE);
  if (StretchBlt(hDcScreenResized, 0, 0, 800, 600,
    hDcScreen, 0, 0, rect.right, rect.bottom, SRCCOPY) == 0)
  {
    printf("Client: StretchBlt is NULL %d\n", GetLastError());
  }

  DeleteObject(hBmpScreen);
  DeleteDC(hDcScreen);

  //Assign new values
  hBmpScreen = hBmpScreenResized;
  hDcScreen = hDcScreenResized;

  SelectObject(hDcScreen, hBmpScreen);

  free((HLOCAL)g_pixels);

  g_pixels = (BYTE *)malloc(g_bmpInfo.bmiHeader.biSizeImage);

  g_bmpInfo.bmiHeader.biWidth = 800;
  g_bmpInfo.bmiHeader.biHeight = 600;

  if (GetDIBits(hDcScreen, hBmpScreen, 0, 600, g_pixels, &g_bmpInfo, DIB_RGB_COLORS) == 0)
  {
    printf("Client: GetDIBits is NULL %d\n", GetLastError());
  }

  DeleteObject(hBmpScreen);
  ReleaseDC(NULL, hDc);
  DeleteDC(hDcScreen);


  //Server side which should take the pixels and paint them on the window
  HDC hDcServer = GetDC(NULL);
  if (hDcServer == NULL)
  {
    printf("Server: hDcServer is NULL %d\n", GetLastError());
  }

  hDcBmpServer = CreateCompatibleDC(hDcServer);
  HBITMAP hBmp;

  hBmp = CreateCompatibleBitmap(hDcServer, g_bmpInfo.bmiHeader.biWidth, g_bmpInfo.bmiHeader.biHeight);
  if (hBmp == NULL)
  {
    printf("Server: hBmp is NULL %d\n", GetLastError());
  }

  SelectObject(hDcBmpServer, hBmp);

  int ScanLines = SetDIBits(hDcBmpServer,
    hBmp,
    0,
    g_bmpInfo.bmiHeader.biHeight,
    g_pixels,
    &g_bmpInfo,
    DIB_RGB_COLORS);

  if (ScanLines == 0)
  {
    printf("Server: hBmp is NULL %d\n", GetLastError());
  }
  else
  {
    printf("Server: Scanned lines %d\n", ScanLines);
  }

  fflush(stdout);

  InvalidateRgn(hWndClient, NULL, TRUE);

  MSG msg;
  while (GetMessage(&msg, NULL, 0, 0) > 0)
  {
    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

Как вы видите, я создаю окно с помощью функции CreateWindows, затем попробуйте сделать снимок экрана, затем я изменил его размер до нужногоразмер окна, который в моем случае составляет 800x600, а затем попробуйте отобразить его с помощью функции InvalidateRgn.Я удалил в основном весь код в WndProc ради этого вопроса и оставил только WM_PAINT part.

Проблема, которую я имею, состоит в том, что окно, которое должно быть заполнено скриншотом, является черным ина нем ничего не отображается.У меня нет ошибок компилятора или времени выполнения, но скриншот не отображается.Я думаю, что мне не хватает информации о том, как сделать это правильно.Надеюсь, что вы можете помочь.

PS

Это исходный код какого-то проекта, я не хочу преобразовывать скриншот в .bmp и отправлять его таким образомЯ хочу понять, почему этот метод не работает.спасибо.

1 Ответ

0 голосов
/ 21 октября 2018

Создание контекста устройства памяти и растрового изображения (дескриптор HBITMAP).Выберите растровое изображение в памяти постоянного тока.Затем используйте BitBlt для копирования с экрана в память постоянного тока.Затем растровое изображение будет содержать данные экрана.

Затем вы можете распечатать дескриптор растрового изображения непосредственно в WM_PAINT.Это будет DDB, его нельзя передавать между программами.Вам нужен DIB, или же используйте GetDIBits для копирования содержимого из растрового изображения в байтовый массив (g_bmpInfo и g_pixels)

Обратите внимание, что размер 24-разрядного растрового изображения не всегда with * height * 3, вам нужна специальная формула для учета заполнения.

BITMAPINFO g_bmpInfo;
BYTE      *g_pixels = NULL;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        auto hdc = BeginPaint(hWnd, &ps);

        RECT rc;
        GetClientRect(hWnd, &rc);

        int w = g_bmpInfo.bmiHeader.biWidth;
        int h = g_bmpInfo.bmiHeader.biHeight;
        if(g_pixels && w && h)
        {
            //print the bitmap on screen
            SetDIBitsToDevice(hdc, 0, 0, w, h, 0, 0, 0, h, g_pixels,
                 &g_bmpInfo, DIB_RGB_COLORS);
        }

        EndPaint(hWnd, &ps);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int main()
{
    CreateWindows();

    RECT rect;
    HWND hWndDesktop = GetDesktopWindow();
    GetWindowRect(hWndDesktop, &rect);
    int width = rect.right - rect.left;
    int height = rect.bottom - rect.top;

    int bpp = 24; //24-bit
    int size = ((width * bpp + 31) / 32) * 4 * height;

    memset(&g_bmpInfo, 0, sizeof(g_bmpInfo));
    g_bmpInfo.bmiHeader.biSize = sizeof(g_bmpInfo.bmiHeader);
    g_bmpInfo.bmiHeader.biWidth = width;
    g_bmpInfo.bmiHeader.biHeight = height;
    g_bmpInfo.bmiHeader.biPlanes = 1;
    g_bmpInfo.bmiHeader.biBitCount = 24;
    g_bmpInfo.bmiHeader.biCompression = BI_RGB;
    g_bmpInfo.bmiHeader.biSizeImage = size;

    g_pixels = new BYTE[size];

    auto hdc = GetDC(HWND_DESKTOP);
    auto memdc = CreateCompatibleDC(hdc);
    auto hbitmap = CreateCompatibleBitmap(hdc, width, height);
    auto oldbmp = SelectObject(memdc, hbitmap);

    //copy from screen to memory    
    BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY);

    //fill g_pixels array
    GetDIBits(hdc, hbitmap, 0, height, g_pixels, &g_bmpInfo, DIB_RGB_COLORS);

    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    //cleanup    
    SelectObject(memdc, oldbmp);
    DeleteObject(hbitmap);
    DeleteDC(memdc);
    ReleaseDC(HWND_DESKTOP, hdc);

    delete[] g_pixels;

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...