WIN32实现远程桌面监控

2024-09-04 48 0

完整代码

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

效果展示

WIN32实现远程桌面监控插图

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/

4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

靶场战神为何会陨落?
漏洞分析与实战分享 | 深入探讨pkexec提权漏洞
postMessage常见安全问题
[Meachines] [Medium] Lightweight LDAP密码嗅探+TRP00F 自…
ofcms V1.2 代码审计(一)
网安内家拳——东西向网络安全是门高级功夫

发布评论