Я новичок в программировании графического интерфейса для 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
и отправлять его таким образомЯ хочу понять, почему этот метод не работает.спасибо.