I am trying to create a light-weight Remote Support Tool. I have everything working except the window keeps drawing the entire window and drilling down until it gets smaller and smaller (See video: https://youtu.be/bwwmfcC_sGs)
I am thinking it is drawing the wrong way to the Window technician side
Client (Supportee program):
#include <WS2tcpip.h>
#include <Windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <winuser.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ws2_32.lib")
#pragma pack(push, 1)
WSAData wData;
WORD ver = MAKEWORD(2, 2);
int main() {
int wsOk = WSAStartup(ver, &wData);
if (wsOk != 0) {
std::cerr << "Error Initializing WinSock! Exiting" << std::endl;
return -1;
}
int x1, y1, x2, y2, w, h;
// Message protocol
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
// Bind IP address to port
std::string ipAddress = "10.0.0.131";
sockaddr_in sockin;
sockin.sin_family = AF_INET;
sockin.sin_port = htons(8081);
inet_pton(AF_INET, ipAddress.c_str(), &sockin.sin_addr);
std::cout << "Attempting to connect to master controller..." << std::endl;
// Connect to server
int connected = connect(sock, (sockaddr*)&sockin, sizeof(sockin)) != SOCKET_ERROR;
if (!connected) {
std::cerr << "Could not connect to server" << std::endl;
return -1;
}
//Only Send the Header once unless the screen resolution changes
int headerSent = 0;
while (connected) {
// get screen dimensions
x1 = GetSystemMetrics(SM_XVIRTUALSCREEN);
y1 = GetSystemMetrics(SM_YVIRTUALSCREEN);
x2 = GetSystemMetrics(SM_CXVIRTUALSCREEN);
y2 = GetSystemMetrics(SM_CYVIRTUALSCREEN);
w = x2 - x1;
h = y2 - y1;
// copy screen to bitmap
HDC hScreen = GetDC(NULL);
HDC hdcCompat = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, w, h);
HGDIOBJ old_obj = SelectObject(hdcCompat, hBitmap);
StretchBlt(hdcCompat, 0, 0, w, h, hScreen, x1, y1, w, h, SRCCOPY);
BITMAP bmpScreen;
GetObject(hBitmap, sizeof(BITMAP), &bmpScreen);
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = w;
bi.biHeight = h;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
HGLOBAL hDIB = GlobalAlloc(GHND, dwBmpSize);
char* lpbitmap = (char*)GlobalLock(hDIB);
// Gets the "bits" from the bitmap, and copies them into a buffer
// that's pointed to by lpbitmap.
GetDIBits(hScreen, hBitmap, 0, (UINT)h, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
if (headerSent == 0) {
std::cout << "Sending BITMAPINFOHEADER..." << std::endl;
if (send(sock, (char*)&bi, sizeof(bi), 0) == SOCKET_ERROR) {
std::cerr << "Failed to send BITMAPINFOHEADER" << std::endl;
break;
}
headerSent = 1;
}
std::cout << "Sending bitmap data..." << std::endl;
if (send(sock, lpbitmap, dwBmpSize, 0) == SOCKET_ERROR) {
std::cerr << "Failed to send bitmap data" << std::endl;
break;
}
GlobalUnlock(hDIB);
GlobalFree(hDIB);
DeleteObject(hBitmap);
DeleteDC(hdcCompat);
ReleaseDC(NULL, hScreen);
Sleep(1000);
}
closesocket(sock);
WSACleanup();
return 0;
}
Server (Technician Side):
#include <WS2tcpip.h>
#include <Windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <winuser.h>
#include <wingdi.h>
#pragma comment(lib, "ws2_32.lib")
#pragma pack(push, 1)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int getTaskBarHeight();
void recvBitmap();
BITMAPINFOHEADER recvBitmapHeader();
HBITMAP hbitTest = { 0 };
BITMAPINFOHEADER bmInfo;
HWND hwnd;
SOCKET clientSocket;
char* buf = 0;
int newWidth = 0;
int newHeight = 0;
bool isReceiving = true;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
WSADATA wData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wData);
if (wsOk != 0) {
std::cerr << "Error Initializing WinSock! Exiting" << std::endl;
return -1;
}
// Create Socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
std::cerr << "could not open socket" << std::endl;
return -1;
}
// Bind IP address to port
sockaddr_in sockin;
sockin.sin_family = AF_INET;
sockin.sin_port = htons(8081);
sockin.sin_addr.S_un.S_addr = INADDR_ANY;
// Bind socket to IP address and port
bind(listening, (sockaddr*)&sockin, sizeof(sockin));
// Tell winsock that socket is for listening
listen(listening, SOMAXCONN);
// Wait for connection
sockaddr_in clientSockAddr;
int clientSize = sizeof(clientSockAddr);
clientSocket = accept(listening, (sockaddr*)&clientSockAddr, &clientSize);
char host[NI_MAXHOST];
char service[NI_MAXSERV];
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
// If client connects
if (getnameinfo((sockaddr*)&clientSockAddr, sizeof(clientSockAddr), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
std::cout << host << " Connection established on: " << service << std::endl;
}
else {
std::cout << "Connection could not be established." << std::endl;
}
bmInfo = recvBitmapHeader();
// Register window class
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"BitmapWindowClass";
RegisterClass(&wc);
// Create the window
hwnd = CreateWindow(L"BitmapWindowClass", L"Client Screen", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, bmInfo.biWidth, bmInfo.biHeight, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
// Main message loop
MSG msg;
while (isReceiving) {
// Check for new data from client
recvBitmap();
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// Create a compatible DC for the bitmap
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hbitTest);
// Draw the bitmap to the window
StretchDIBits(hdc, 0, 0, bmInfo.biWidth, bmInfo.biHeight - getTaskBarHeight(), 0, 0, bmInfo.biWidth,
bmInfo.biHeight, buf, (BITMAPINFO*)&bmInfo, DIB_RGB_COLORS, SRCCOPY);
// Clean up
/*SelectObject(hdcMem, hOldBitmap);
DeleteDC(hdcMem);
DeleteDC(hdc);
DeleteObject(hOldBitmap);
EndPaint(hwnd, &ps);*/
delete[] buf;
return 0;
}
case WM_SIZE: {
// Update the bitmap size based on the new window size
newWidth = LOWORD(lParam);
newHeight = HIWORD(lParam);
// Invalidate the window to trigger a repaint
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
return 0;
}
case WM_CLOSE:
DestroyWindow(hwnd);
WSACleanup();
return 0;
case WM_DESTROY:
DeleteObject(hbitTest);
PostQuitMessage(0);
WSACleanup();
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int getTaskBarHeight() {
RECT rect;
SystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, NULL);
return bmInfo.biHeight - rect.bottom;
}
void recvBitmap() {
buf = new char[((((bmInfo.biWidth * 32 + 31) / 32) * 4) * bmInfo.biHeight) + 1];
ZeroMemory(buf, ((((bmInfo.biWidth * 32 + 31) / 32) * 4) * bmInfo.biHeight) + 1);
int bitmapRec = recv(clientSocket, buf, ((((bmInfo.biWidth * 32 + 31) / 32) * 4) * bmInfo.biHeight) + 1, NULL);
if (bitmapRec <= 0) {
isReceiving = false;
}
std::cout << "receive bitmap bytes: " << bitmapRec << " " << WSAGetLastError() << std::endl;
/*HDC recHdc = GetDC(NULL);
HDC recMem = CreateCompatibleDC(recHdc);
hbitTest = CreateCompatibleBitmap(recHdc, bmInfo.biWidth, bmInfo.biHeight);
HGDIOBJ old_obj = SelectObject(recMem, hbitTest);*/
}
BITMAPINFOHEADER recvBitmapHeader() {
// Receive the bitmap info header
char* bitmapInfo = new char[sizeof(BITMAPINFOHEADER)];
int rec = recv(clientSocket, bitmapInfo, sizeof(BITMAPINFOHEADER), NULL);
if (rec <= 0) {
isReceiving = false;
delete[] bitmapInfo;
}
std::cout << "bytes received bitmap info " << rec << std::endl;
memcpy(&bmInfo, bitmapInfo, sizeof(BITMAPINFOHEADER));
delete[] bitmapInfo;
delete[] buf; // Free previous buffer
return bmInfo;
}