WIN32实现远程桌面监控

news2024/9/20 0:36:01

文章目录

    • 完整代码
      • API简介
      • 调试代码
    • 后记
    • reference

完整代码

server.cpp

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#include <vector>
#pragma comment(lib, "ws2_32.lib")

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void RenderBitmap(HDC hdc, BYTE* bBits, int width, int height, int windowWidth, int windowHeight);

class xy {
public:
    int x;
    int y;
};

int main(void)
{
    // Initialize WinSock
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);  // Port number
    inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);
    bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
    listen(serverSocket, 5);

    // Wait for client connection
    SOCKET clientSocket = accept(serverSocket, NULL, NULL);
    xy data;
    recv(clientSocket, (char*)&data, sizeof(data), 0);

    // Register window class
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"ScreenCaptureReceiverWindowClass";
    RegisterClass(&wc);

    // Set up the bitmap for rendering
    BITMAPINFO bInfo;
    HBITMAP hBitmap;
    BYTE* bBits = nullptr;
    int screenWidth = data.x;  // Set screen width
    int screenHeight = data.y; // Set screen height
    int windowWidth = 800;
    int windowHeight = 600;
    float screenAspect = (float)screenWidth / screenHeight;
    float windowAspect = (float)windowWidth / windowHeight;
    // Adjust window size to maintain the screen aspect ratio
    if (screenAspect > windowAspect)
    {
        windowHeight = (INT)(windowWidth / screenAspect);
    }
    else
    {
        windowWidth = (INT)(windowHeight * screenAspect);
    }
    RECT rect = { 0, 0, windowWidth, windowHeight };
    AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bInfo.bmiHeader.biBitCount = 24;
    bInfo.bmiHeader.biCompression = BI_RGB;
    bInfo.bmiHeader.biPlanes = 1;
    bInfo.bmiHeader.biWidth = screenWidth;
    bInfo.bmiHeader.biHeight = -screenHeight;  // Top-down 
    HWND hwnd = CreateWindowEx(0, wc.lpszClassName, L"Screen Receiver", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, wc.hInstance, NULL);
    ShowWindow(hwnd, SW_SHOW);
    HDC hdc = GetDC(hwnd);
    hBitmap = CreateDIBSection(hdc, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);

    // Main message loop
    MSG msg = { 0 };
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // Receive image data from the client
            int len = screenWidth * screenHeight * 3;
            recv(clientSocket, (char*)bBits, len, 0);

            // Render the received bitmap
            RenderBitmap(hdc, bBits, screenWidth, screenHeight, windowWidth, windowHeight);

            Sleep(200);  // Adjust the refresh rate
        }
    }

    // Clean up
    DeleteObject(hBitmap);
    ReleaseDC(hwnd, hdc);
    closesocket(clientSocket);
    closesocket(serverSocket);
    WSACleanup();
    return 0;
}

void RenderBitmap(HDC hdc, BYTE* bBits, int width, int height, int windowWidth, int windowHeight)
{
    BITMAPINFO bInfo;
    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bInfo.bmiHeader.biBitCount = 24;
    bInfo.bmiHeader.biCompression = BI_RGB;
    bInfo.bmiHeader.biPlanes = 1;
    bInfo.bmiHeader.biWidth = width;
    bInfo.bmiHeader.biHeight = -height;
    SetStretchBltMode(hdc, HALFTONE);

    StretchDIBits(hdc, 0, 0, windowWidth, windowHeight, 0, 0, width, height, bBits, &bInfo, DIB_RGB_COLORS, SRCCOPY);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

client.cpp

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <vector>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
std::vector<int> getxy();
class xyz {
public:
    int x;
    int y;
};
int main(void)
{
    // Initialize WinSock
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);  // Port number

    inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);// Replace with the server's IP address
    connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));

    // Get screen dimensions
    vector<int> xy = getxy();
    int screenWidth = xy[0];
    int screenHeight = xy[1];
    xyz data;
    data.x = screenWidth;
    data.y = screenHeight;
    send(clientSocket, (char*)&data, sizeof(data), 0);

    // Set up the screen capture
    BITMAPINFO bInfo;
    HDC hDC, hMemDC;
    HBITMAP hBitmap;
    BYTE* bBits = NULL;

    hDC = GetDC(NULL);
    hMemDC = CreateCompatibleDC(hDC);

    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bInfo.bmiHeader.biBitCount = 24;
    bInfo.bmiHeader.biCompression = BI_RGB;
    bInfo.bmiHeader.biPlanes = 1;
    bInfo.bmiHeader.biWidth = screenWidth;
    bInfo.bmiHeader.biHeight = -screenHeight;
    hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);
    SelectObject(hMemDC, hBitmap);

    int len = screenWidth * screenHeight * 3;

    // Main loop to capture and send screen data
    while (true)
    {
        BitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);
        send(clientSocket, (char*)bBits, len, 0);

        Sleep(20);  // Adjust the sending rate
    }

    // Clean up
    DeleteObject(hBitmap);
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hDC);
    closesocket(clientSocket);
    WSACleanup();

    return 0;
}

std::vector<int> getxy() {
    HWND hWnd = GetDesktopWindow();//根据需要可以替换成自己程序的句柄 
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);

    DEVMODE dm;
    MONITORINFOEX miex;
    dm.dmSize = sizeof(dm);
    dm.dmDriverExtra = 0;
    miex.cbSize = sizeof(miex);
    GetMonitorInfo(hMonitor, &miex);
    // 获取监视器物理宽度与高度
    EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
    int cxPhysical = dm.dmPelsWidth;
    int cyPhysical = dm.dmPelsHeight;
    vector<int> ret;
    ret.push_back(cxPhysical);
    ret.push_back(cyPhysical);

    return ret;
}

效果展示

在这里插入图片描述

API简介

WSAStartup

int WSAAPI WSAStartup(
  [in]  WORD      wVersionRequested,
  [out] LPWSADATA lpWSAData
);

wsastartup

  1. 初始化 Winsock 库:加载并初始化 Winsock 库的必要组件。
  2. 版本检查:应用程序可以通过 WSAStartup 指定所需的 Winsock 版本,同时函数会返回实际初始化的版本信息。
  3. 资源分配:为应用程序的网络操作分配必要的资源。

调用 WSAStartup 成功后,应用程序才能继续进行网络编程。当应用程序完成所有网络操作后,应调用 WSACleanup 函数来释放资源并终止 Winsock 使用。

inet_pton/inet_ntop

这两个函数是随IPv6出现的函数,对于IPv4地址和IPv6地址都适用,函数中p和n分别代表表达(presentation)和数值(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构的二进制值。
int inet_pton(int family, const char *strptr, void *addrptr);     
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

StretchBlt /BitBlt/StretchDIBits

StretchBltBitBlt 是 Windows GDI(图形设备接口)中的两个函数,用于在设备上下文(Device Context,DC)之间进行位图的复制和绘制操作。它们的主要区别在于是否进行图像的缩放。StretchDIBits从 DIB 数据(通常存储在内存中)到设备上下文进行更灵活的图像处理

调试代码

屏幕截屏

#include<stdio.h>
#include<windows.h>
#include<string>
#include<iostream>
using namespace std;
int main(void)
{
    BITMAPFILEHEADER bfHeader;
    BITMAPINFOHEADER biHeader;
    BITMAPINFO bInfo;
    HGDIOBJ hTempBitmap;
    HBITMAP hBitmap;
    BITMAP bAllDesktops;
    HDC hDC, hMemDC;
    LONG lWidth, lHeight;
    BYTE* bBits = NULL;
    HANDLE hHeap = GetProcessHeap();
    DWORD cbBits, dwWritten = 0;
    HANDLE hFile;
    INT x = GetSystemMetrics(SM_XVIRTUALSCREEN);
    INT y = GetSystemMetrics(SM_YVIRTUALSCREEN);

    ZeroMemory(&bfHeader, sizeof(BITMAPFILEHEADER));
    ZeroMemory(&biHeader, sizeof(BITMAPINFOHEADER));
    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    ZeroMemory(&bAllDesktops, sizeof(BITMAP));

    hDC = GetDC(NULL);
    hTempBitmap = GetCurrentObject(hDC, OBJ_BITMAP);
    GetObjectW(hTempBitmap, sizeof(BITMAP), &bAllDesktops);

    lWidth = bAllDesktops.bmWidth;
    lHeight = bAllDesktops.bmHeight;
    //get lWidth lHeight

    DeleteObject(hTempBitmap);

    bfHeader.bfType = (WORD)('B' | ('M' << 8));//小端存储BM
    bfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    biHeader.biSize = sizeof(BITMAPINFOHEADER);
    biHeader.biBitCount = 24;
    biHeader.biCompression = BI_RGB;
    biHeader.biPlanes = 1;
    biHeader.biWidth = lWidth;
    biHeader.biHeight = lHeight;

    bInfo.bmiHeader = biHeader;

    cbBits = (((24 * lWidth + 31) & ~31) / 8) * lHeight;//~31 相当于将最低 5 位全置为 0,保证是32的倍数(四字节对齐)

    hMemDC = CreateCompatibleDC(hDC);
    hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);
    SelectObject(hMemDC, hBitmap);
    BitBlt(hMemDC, 0, 0, lWidth, lHeight, hDC, x, y, SRCCOPY);
    string path = "D:\\c_project\\dlltest\\a.bmp";
    hFile = CreateFileA(path.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (INVALID_HANDLE_VALUE == hFile)
    {
        DeleteDC(hMemDC);
        ReleaseDC(NULL, hDC);
        DeleteObject(hBitmap);

        return FALSE;
    }
    WriteFile(hFile, &bfHeader, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
    WriteFile(hFile, &biHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
    WriteFile(hFile, bBits, cbBits, &dwWritten, NULL);
    FlushFileBuffers(hFile);
    CloseHandle(hFile);

    DeleteDC(hMemDC);
    ReleaseDC(NULL, hDC);
    DeleteObject(hBitmap);

    return TRUE;
}

保存的时刻为代码运行到BitBlt时刻的图像

本地实时渲染

#include <windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include<vector>
using namespace std;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
std::vector<int> getxy();
int main(void)
{
    // Register window class
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"ScreenCaptureWindowClass";
    RegisterClass(&wc);

    // Get screen dimensions
    vector<int> xy = getxy();
    int screenWidth = xy[0];
    int screenHeight = xy[1];

    // Define the desired window size (e.g., 800x600)
    INT windowWidth = 800;
    INT windowHeight = 600;

    // Calculate aspect ratios
    float screenAspect = (float)screenWidth / screenHeight;
    float windowAspect = (float)windowWidth / windowHeight;

    // Adjust window size to maintain the screen aspect ratio
    if (screenAspect > windowAspect)
    {
        windowHeight = (INT)(windowWidth / screenAspect);
    }
    else
    {
        windowWidth = (INT)(windowHeight * screenAspect);
    }

    // Calculate window size including borders and title bar
    RECT rect = { 0, 0, windowWidth, windowHeight };
    AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

    // Create window
    HWND hwnd = CreateWindowEx(0, wc.lpszClassName, L"Screen Capture", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, wc.hInstance, NULL);
    ShowWindow(hwnd, SW_SHOW);

    // Set up the screen capture
    BITMAPINFO bInfo;
    HDC hDC, hMemDC;
    HBITMAP hBitmap;
    BYTE* bBits = NULL;

    hDC = GetDC(NULL);
    hMemDC = CreateCompatibleDC(hDC);

    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bInfo.bmiHeader.biBitCount = 24;
    bInfo.bmiHeader.biCompression = BI_RGB;
    bInfo.bmiHeader.biPlanes = 1;
    bInfo.bmiHeader.biWidth = screenWidth;
    bInfo.bmiHeader.biHeight = -screenHeight;  // Negative height to indicate top-down DIB
    hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);
    SelectObject(hMemDC, hBitmap);

    // Main message loop
    MSG msg = { 0 };
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // Capture the screen
            BitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);

            // Get the device context of the window
            HDC hWindowDC = GetDC(hwnd);

            // Scale and paint the captured screen to fit the window size
            SetStretchBltMode(hWindowDC, HALFTONE);
            StretchBlt(hWindowDC, 0, 0, windowWidth, windowHeight, hMemDC, 0, 0, screenWidth, screenHeight, SRCCOPY);

            ReleaseDC(hwnd, hWindowDC);

            // Sleep for 0.2 seconds (200 milliseconds)
            //Sleep(200);
        }
    }

    // Clean up
    DeleteObject(hBitmap);
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hDC);

    return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
std::vector<int> getxy() {
    HWND hWnd = GetDesktopWindow();//根据需要可以替换成自己程序的句柄 
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);

    DEVMODE dm;
    MONITORINFOEX miex;
    dm.dmSize = sizeof(dm);
    dm.dmDriverExtra = 0;
    miex.cbSize = sizeof(miex);
    GetMonitorInfo(hMonitor, &miex);
    // 获取监视器物理宽度与高度
    EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
    int cxPhysical = dm.dmPelsWidth;
    int cyPhysical = dm.dmPelsHeight;
    vector<int> ret;
    ret.push_back(cxPhysical);
    ret.push_back(cyPhysical);

    return ret;
}

传输渲染

#include <windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include<vector>
using namespace std;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
std::vector<int> getxy();

int main(void)
{
    // Register window class
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"ScreenCaptureWindowClass";
    RegisterClass(&wc);

    // Get screen dimensions
    vector<int> xy = getxy();
    int screenWidth = xy[0];
    int screenHeight = xy[1];

    // Define the desired window size (e.g., 800x600)
    INT windowWidth = 800;
    INT windowHeight = 600;

    // Calculate aspect ratios
    float screenAspect = (float)screenWidth / screenHeight;
    float windowAspect = (float)windowWidth / windowHeight;

    // Adjust window size to maintain the screen aspect ratio
    if (screenAspect > windowAspect)
    {
        windowHeight = (INT)(windowWidth / screenAspect);
    }
    else
    {
        windowWidth = (INT)(windowHeight * screenAspect);
    }

    // Calculate window size including borders and title bar
    RECT rect = { 0, 0, windowWidth, windowHeight };
    AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

    // Create window
    HWND hwnd = CreateWindowEx(0, wc.lpszClassName, L"Screen Capture", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, wc.hInstance, NULL);
    ShowWindow(hwnd, SW_SHOW);

    // Set up the screen capture
    BITMAPINFO bInfo;
    HDC hDC, hMemDC;
    HBITMAP hBitmap;
    BYTE* bBits = NULL;

    hDC = GetDC(NULL);
    hMemDC = CreateCompatibleDC(hDC);

    ZeroMemory(&bInfo, sizeof(BITMAPINFO));
    bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bInfo.bmiHeader.biBitCount = 24;
    bInfo.bmiHeader.biCompression = BI_RGB;
    bInfo.bmiHeader.biPlanes = 1;
    bInfo.bmiHeader.biWidth = screenWidth;
    bInfo.bmiHeader.biHeight = -screenHeight;  // Negative height to indicate top-down DIB
    hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);
    SelectObject(hMemDC, hBitmap);
    int len = screenWidth * screenHeight * 3;
    // Allocate a buffer for storing the screen data
    BYTE* screenBuffer = new BYTE[len]; // 24-bit color

    // Main message loop
    MSG msg = { 0 };
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // Capture the screen into buffer
            BitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);
            memcpy(screenBuffer, bBits, len); // Copy screen data to buffer

            // Get the device context of the window
            HDC hWindowDC = GetDC(hwnd);

            // Create a compatible bitmap from buffer data
            HBITMAP hBufferBitmap = CreateCompatibleBitmap(hWindowDC, screenWidth, screenHeight);
            HDC hBufferDC = CreateCompatibleDC(hWindowDC);
            SelectObject(hBufferDC, hBufferBitmap);

            // Copy buffer data into the bitmap
            SetDIBits(hBufferDC, hBufferBitmap, 0, screenHeight, screenBuffer, &bInfo, DIB_RGB_COLORS);

            // Scale and paint the buffered screen to fit the window size
            SetStretchBltMode(hWindowDC, HALFTONE);
            StretchBlt(hWindowDC, 0, 0, windowWidth, windowHeight, hBufferDC, 0, 0, screenWidth, screenHeight, SRCCOPY);

            // Clean up
            DeleteObject(hBufferBitmap);
            DeleteDC(hBufferDC);
            ReleaseDC(hwnd, hWindowDC);

            // Sleep for 0.2 seconds (200 milliseconds)
            Sleep(200);
        }
    }

    // Clean up
    delete[] screenBuffer;
    DeleteObject(hBitmap);
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hDC);

    return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

std::vector<int> getxy() {
    HWND hWnd = GetDesktopWindow();//根据需要可以替换成自己程序的句柄 
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);

    DEVMODE dm;
    MONITORINFOEX miex;
    dm.dmSize = sizeof(dm);
    dm.dmDriverExtra = 0;
    miex.cbSize = sizeof(miex);
    GetMonitorInfo(hMonitor, &miex);
    // 获取监视器物理宽度与高度
    EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
    int cxPhysical = dm.dmPelsWidth;
    int cyPhysical = dm.dmPelsHeight;
    vector<int> ret;
    ret.push_back(cxPhysical);
    ret.push_back(cyPhysical);

    return ret;
}

参数传递

// 发送结构体
xy data;
data.x = 10;
data.y = 20;
send(clientSocket, (char *) & data, sizeof(data), 0);

//接受结构体
 xy data;
 recv(clientSocket, (char*) & data, sizeof(data), 0);
 std::cout << "Received: x = " << data.x << ", y = " << data.y << std::endl;

后记

BitBlt (Bit Block Transfer)

BitBlt 函数用于从一个设备上下文复制一个位图区域到另一个设备上下文。它不进行任何缩放操作,原样复制位图。通常用于在同一尺寸的区域之间移动或绘制位图。

函数原型:

cpp复制代码BOOL BitBlt(
  HDC   hdcDest,   // 目标设备上下文句柄
  int   nXDest,    // 目标矩形左上角的 X 坐标
  int   nYDest,    // 目标矩形左上角的 Y 坐标
  int   nWidth,    // 目标矩形的宽度
  int   nHeight,   // 目标矩形的高度
  HDC   hdcSrc,    // 源设备上下文句柄
  int   nXSrc,     // 源矩形左上角的 X 坐标
  int   nYSrc,     // 源矩形左上角的 Y 坐标
  DWORD dwRop      // 光栅操作代码
);

主要特性:

  • 复制图像:从源设备上下文复制图像到目标设备上下文,不进行缩放。
  • 位块传输:按照指定的矩形区域进行传输。

应用场景:

  • 同尺寸位图:适用于源和目标位图区域尺寸相同的情况下的快速复制操作。
  • 简单绘制:用于简单的图像绘制、窗口背景绘制等。

StretchBlt (Stretch Bit Block Transfer)

StretchBlt 函数与 BitBlt 类似,但它可以在复制位图时进行缩放。目标区域和源区域的大小可以不同,StretchBlt 会自动调整图像的尺寸,使之适应目标矩形。

函数原型:

cpp复制代码BOOL StretchBlt(
  HDC   hdcDest,     // 目标设备上下文句柄
  int   nXOriginDest,// 目标矩形左上角的 X 坐标
  int   nYOriginDest,// 目标矩形左上角的 Y 坐标
  int   nWidthDest,  // 目标矩形的宽度
  int   nHeightDest, // 目标矩形的高度
  HDC   hdcSrc,      // 源设备上下文句柄
  int   nXOriginSrc, // 源矩形左上角的 X 坐标
  int   nYOriginSrc, // 源矩形左上角的 Y 坐标
  int   nWidthSrc,   // 源矩形的宽度
  int   nHeightSrc,  // 源矩形的高度
  DWORD dwRop        // 光栅操作代码
);

主要特性:

  • 缩放图像:支持对位图进行缩放,目标区域可以比源区域大或小。
  • 比例变换:自动调整图像比例,使其适应目标区域。

应用场景:

  • 图像缩放:用于在图像渲染时需要缩放、拉伸或压缩的场景,如缩略图显示、窗口大小变化时的图像调整等。
  • 动态布局:在需要根据设备上下文的大小动态调整图像显示时,StretchBlt 是合适的选择。

总结

  • BitBlt:直接复制图像,不进行缩放,适合源和目标区域大小一致的情况下。
  • StretchBlt:支持缩放,在复制图像时根据需要调整尺寸,适合在不同大小区域之间传输图像的场景。

字符转化

class Char {
public:
    static std::wstring AtoW(const std::string& str)
    {
        int wcLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
        std::wstring newBuf;
        newBuf.resize(wcLen);
        MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, (LPWSTR)newBuf.c_str(), wcLen);
        return newBuf;
    }

    static std::string WtoA(const std::wstring& str)
    {
        int cLen = WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, NULL, 0, 0, NULL);
        std::string newBuf;
        newBuf.resize(cLen);
        WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, (char*)newBuf.c_str(), cLen, 0, NULL);
        return newBuf;
    }
};

reference

https://geocld.github.io/2021/03/02/bmp/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2076950.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是韦恩图,怎么制作?用这款软件在线绘制,简单又好用!

在日常工作和学习中&#xff0c;我们经常需要用图表来可视化呈现复杂的信息和关系。其中&#xff0c;韦恩图是一种简洁而强大的可视化工具&#xff0c;能够清晰地展现集合之间的关系&#xff0c;诸如包含与被包含、互斥、并列等。 不过对刚接触韦恩图的人而言&#xff0c;或多…

traceroute命令这样用,追踪主机路由没烦恼

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 网络的稳定性和可靠性对于业务连续性至关重要。当涉及到网络连接问题时&#xff0c;有一个强大的工具就是 tr…

Certum Domain Validation CA SHA2

Certum是波兰的一家数字证书厂家&#xff0c;该机构也是目前世界第四家兼容性在99%机构&#xff08;包括历史版本浏览器&#xff09;&#xff0c;目前在国内有授权提供商&#xff1a;Gworg提供签发和认证&#xff0c;拥有二级代理划分&#xff0c;适合长期做SSL证书业务或者集成…

年薪100K入职字节测试岗现在分享下我常背的软件测试面试题

800道软件测试面试真题&#xff0c;高清打印版打包带走&#xff0c;横扫软件测试面试高频问题&#xff0c;涵盖测试理论、Linux、MySQL、Web测试、接口测试、APP测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块面试题&am…

Linux文件编程(系统API调用)

文章目录 Linux文件编程标注C的IO缓存类型代码示例--缓存区的存在 文件I/O系统调用标准C库关于文件的输入输出函数FILE结构体文件描述符文件描述符与文件指针的相互转换 系统调用常用函数open函数&#xff08;打开或者创建文件&#xff09;creat函数&#xff08;创建一个现有文…

JAVA-封装

目录 一、封装的概念 二、封装扩展之包 1. 包的概念 2.导入包中的类 3.自定义包 4.常见的包 三、访问限定符 在同一包中&#xff1a; 在不同包中&#xff1a;​编辑 一、封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主…

ESP32修改分区表

修改分区表 官方参考 在工程目录文件夹新建分区表&#xff0c;参考官方的写就行&#xff0c;我这里改成了8M的FLASH&#xff0c;所以新建的分区表为名字是 default_8MB.csv &#xff0c;内容如下&#xff1a; # Name, Type, SubType, Offset, Size, Flags nvs, data, …

后端微服务与分布式系统

编写一篇关于后端微服务和分布式系统的文档&#xff0c;需要详细讨论微服务架构的核心概念、优缺点、关键技术&#xff0c;以及在分布式系统中的应用。以下是文档的大纲和内容概述&#xff1a; 后端微服务与分布式系统 1. 简介 微服务架构是一种将大型应用程序分解为一系列小…

leetCode - - - 二叉树

目录​​​​​​​ 1.前中后序遍历&#xff08;递归&#xff09; 2.前中后序遍历&#xff08;迭代&#xff09; 3.翻转二叉树&#xff08;LeetCode 226&#xff09; 4.最大二叉树&#xff08; LeetCode 654 &#xff09; 5.平衡二叉树&#xff08; LeetCode 110 &#xf…

02- javascript 高阶-构造函数(知识点)呀

目录 1.构造函数 1.1 JS构造函数的实例成员和静态成员 1.1.1实例成员 1.1.2静态成员 1.2构造函数原型prototype 1.3对象原型 1.4 constructor构造函数 1.5原型链 1.6构造函数实例和原型对象三角关系 1.7原型链和成员的查找机制 1.7.1 Object.prototype.hasOwnPropert…

WEB渗透Win提权篇-提权工具合集

提权工具合集包&#xff1a; 夸克网盘分享 往期文章 WEB渗透Win提权篇-RDP&Firewall-CSDN博客 WEB渗透Win提权篇-MSSQL-CSDN博客 WEB渗透Win提权篇-MYSQL-udf-CSDN博客 WEB渗透Win提权篇-AccountSpoofing-CSDN博客 WEB渗透Win提权篇-弱权限提权-CSDN博客 Tools合集 工…

UVa1670/LA5920 Kingdom Roadmap

UVa1670/LA5920 Kingdom Roadmap 题目链接题意分析AC 代码 题目链接 本题是2011年icpc欧洲区域赛东北欧赛区的K题 题意 输入一个n&#xff08;n≤100000&#xff09;个结点的树&#xff0c;添加尽量少的边&#xff0c;使得任意删除一条边之后图仍然连通。如下图所示&#xff0…

如果是你,你会背叛师门吗?看了凌晨一点杭州隧道里睡满的外卖员,我觉得李佳琦被骂一点也不冤——早读(逆天打工人爬取热门微信文章解读)

如果是你&#xff0c;你会背叛师门吗&#xff1f;&#xff1f; 引言Python 代码第一篇 洞见 看了凌晨一点杭州隧道里睡满的外卖员&#xff0c;我觉得李佳琦被骂一点也不冤第二篇 股市风云结尾 (先不论人品如何&#xff0c;这个问题就有点类似董宇辉跟新东方&#xff0c;大伙且看…

Java学习第一天

Java介绍&#xff1a; Java是一种高级编程语言&#xff1b;由sun公司研发&#xff0c;之后被Oracle公司收购&#xff1b;Java之父是詹姆斯.高斯林&#xff1b;Java什么都能做但主要用于企业互联网系统的开发&#xff1b;包括JavaSE&#xff08;标准版&#xff09;、JavaEE&…

C程序设计——表达式的值0

表达式 表达式是一组序列&#xff0c;由操作符或操作数组成。 表达式的值 C语言中&#xff0c;所有的表达式&#xff0c;都是有值的&#xff0c;所以本节专门讲讲表达式的值。 算数表达式 算数表达式的值&#xff0c;就是算数运算的结果&#xff0c;比如表达式 1 1的值就…

Threejs三要素及demo

本文目录 前言一、threejs三要素1.1 场景Scene1.2 相机Camera1.3 渲染器Renderer1.4 项目构建准备 二、安装Threejs2.1 编写代码 前言 Three.js是一个在 MIT 许可下的 JavaScript 库&#xff0c;它在 WebGL 之上运行。这个库的目标就是简化处理3D内容的过程。它是一个WebGL引擎…

【Linux】第一次使用linux向gitee上提交代码

1.首先要在gitee上新建一个仓库 2.然后&#xff0c;复制https的仓库链接 3. 三板斧 第一斧 git add . 4.三板斧 第二斧 git commit -m ‘日志’ 5.三板斧 第三斧 git push

QQ官方BOT 机器人Python实现群聊本地图片【base64编码】上传及其发送

参考&#xff1a;实现群聊本地图片【base64编码】上传及其发送 by SlieFamily 拉取请求 #199 腾讯连接/Botpy (github.com) 首先找到api.py&#xff0c;如果你是通过pip安装的botpy。找到包对应的地址&#xff0c;如果是clone的&#xff0c;也直接找到api.py。 打开后&#xff…

io进程----文件io

目录 一丶概念 二丶特点 三丶函数 1.打开文件 open 2.关闭文件 close 3.读取文件 read 4.写入文件 write 5.文件定位操作 标准IO和文件IO区别 四丶获取文件属性 1.stat函数 2.获取文件类型 五丶目录操作 一丶概念 在posix(可移植操作系统接口)中定义的一组输入输出…

STC89C52 定时器浅谈

文章目录 1、定时器1.1 定时器简介1.2 定时器构成1.2.1 系统时钟1.2.2 计数单元1.2.3 中断系统 1.2 定时器0/1的相关寄存器1.2.1 TMOD1.2.2 TCON 1.3 初始化定时器0 1、定时器 1.1 定时器简介 定时器&#xff0c;又称为计数器&#xff0c;是51单片机的内部资源&#xff0c;即…