WIN32实现远程桌面监控

文章目录

    • 完整代码
      • 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 WinSockWSADATA 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 numberinet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));listen(serverSocket, 5);// Wait for client connectionSOCKET clientSocket = accept(serverSocket, NULL, NULL);xy data;recv(clientSocket, (char*)&data, sizeof(data), 0);// Register window classWNDCLASS wc = { 0 };wc.lpfnWndProc = WndProc;wc.hInstance = GetModuleHandle(NULL);wc.lpszClassName = L"ScreenCaptureReceiverWindowClass";RegisterClass(&wc);// Set up the bitmap for renderingBITMAPINFO bInfo;HBITMAP hBitmap;BYTE* bBits = nullptr;int screenWidth = data.x;  // Set screen widthint screenHeight = data.y; // Set screen heightint windowWidth = 800;int windowHeight = 600;float screenAspect = (float)screenWidth / screenHeight;float windowAspect = (float)windowWidth / windowHeight;// Adjust window size to maintain the screen aspect ratioif (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 loopMSG 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 clientint len = screenWidth * screenHeight * 3;recv(clientSocket, (char*)bBits, len, 0);// Render the received bitmapRenderBitmap(hdc, bBits, screenWidth, screenHeight, windowWidth, windowHeight);Sleep(200);  // Adjust the refresh rate}}// Clean upDeleteObject(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 WinSockWSADATA 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 numberinet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);// Replace with the server's IP addressconnect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));// Get screen dimensionsvector<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 captureBITMAPINFO 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 datawhile (true){BitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);send(clientSocket, (char*)bBits, len, 0);Sleep(20);  // Adjust the sending rate}// Clean upDeleteObject(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 lHeightDeleteObject(hTempBitmap);bfHeader.bfType = (WORD)('B' | ('M' << 8));//小端存储BMbfHeader.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 classWNDCLASS wc = { 0 };wc.lpfnWndProc = WndProc;wc.hInstance = GetModuleHandle(NULL);wc.lpszClassName = L"ScreenCaptureWindowClass";RegisterClass(&wc);// Get screen dimensionsvector<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 ratiosfloat screenAspect = (float)screenWidth / screenHeight;float windowAspect = (float)windowWidth / windowHeight;// Adjust window size to maintain the screen aspect ratioif (screenAspect > windowAspect){windowHeight = (INT)(windowWidth / screenAspect);}else{windowWidth = (INT)(windowHeight * screenAspect);}// Calculate window size including borders and title barRECT rect = { 0, 0, windowWidth, windowHeight };AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);// Create windowHWND 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 captureBITMAPINFO 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 DIBhBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID**)&bBits, NULL, 0);SelectObject(hMemDC, hBitmap);// Main message loopMSG msg = { 0 };while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{// Capture the screenBitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);// Get the device context of the windowHDC hWindowDC = GetDC(hwnd);// Scale and paint the captured screen to fit the window sizeSetStretchBltMode(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 upDeleteObject(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 classWNDCLASS wc = { 0 };wc.lpfnWndProc = WndProc;wc.hInstance = GetModuleHandle(NULL);wc.lpszClassName = L"ScreenCaptureWindowClass";RegisterClass(&wc);// Get screen dimensionsvector<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 ratiosfloat screenAspect = (float)screenWidth / screenHeight;float windowAspect = (float)windowWidth / windowHeight;// Adjust window size to maintain the screen aspect ratioif (screenAspect > windowAspect){windowHeight = (INT)(windowWidth / screenAspect);}else{windowWidth = (INT)(windowHeight * screenAspect);}// Calculate window size including borders and title barRECT rect = { 0, 0, windowWidth, windowHeight };AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);// Create windowHWND 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 captureBITMAPINFO 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 DIBhBitmap = 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 dataBYTE* screenBuffer = new BYTE[len]; // 24-bit color// Main message loopMSG msg = { 0 };while (msg.message != WM_QUIT){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}else{// Capture the screen into bufferBitBlt(hMemDC, 0, 0, screenWidth, screenHeight, hDC, 0, 0, SRCCOPY);memcpy(screenBuffer, bBits, len); // Copy screen data to buffer// Get the device context of the windowHDC hWindowDC = GetDC(hwnd);// Create a compatible bitmap from buffer dataHBITMAP hBufferBitmap = CreateCompatibleBitmap(hWindowDC, screenWidth, screenHeight);HDC hBufferDC = CreateCompatibleDC(hWindowDC);SelectObject(hBufferDC, hBufferBitmap);// Copy buffer data into the bitmapSetDIBits(hBufferDC, hBufferBitmap, 0, screenHeight, screenBuffer, &bInfo, DIB_RGB_COLORS);// Scale and paint the buffered screen to fit the window sizeSetStretchBltMode(hWindowDC, HALFTONE);StretchBlt(hWindowDC, 0, 0, windowWidth, windowHeight, hBufferDC, 0, 0, screenWidth, screenHeight, SRCCOPY);// Clean upDeleteObject(hBufferBitmap);DeleteDC(hBufferDC);ReleaseDC(hwnd, hWindowDC);// Sleep for 0.2 seconds (200 milliseconds)Sleep(200);}}// Clean updelete[] 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.rhkb.cn/news/409642.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费JSON在线解析工具网址

1&#xff0c;https://tool.juhe.cn/ JSON在线解析 (juhe.cn) 2&#xff0c;https://www.sojson.com/ JSON在线 | JSON解析格式化—SO JSON在线工具

Android Studio:模拟器页面闪烁,手机模拟器输入画面闪烁 android studio闪屏

主要解决&#xff0c;android studio 启动app测试&#xff0c;输入数据时&#xff0c;手机画面就会闪烁&#xff0c;闪屏 1. 如图所示&#xff0c;依照顺序找到Edit &#xff0c;并点击Edit 2. 找到Graphics 选择为SoftWare &#xff0c;并保存修改即可 3. 如果此处不能选择S…

MongoDB Compass初体验

入坑Mongodb也好多年了&#xff0c;客户端一直都是使用的Robomongo&#xff0c;后改名为Robo 3T了&#xff0c;现在又改名为Studio 3T&#xff0c;还分了免费版和付费版。 最近换了新电脑&#xff0c;需要重新安装Mongodb的客户端&#xff0c;加上公司对安装软件的各种限制&…

【C语言报错已解决】 `Buffer Overflow`

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言一、问题描述&#x1f469;‍&#x1f52c;报错示例&#x1f4da;报错分析&#x1f4da;解决思路 二、解决方法&a…

加速自动驾驶模型迭代,数据存算一体是关键

自动驾驶的每一个业务阶段都会涉及到 AI 深度学习算法和算力的参与&#xff0c;机器视觉&#xff0c;深度学习&#xff0c;传感器技术等均在自动驾驶领域发挥着重要的作用。自动驾驶系统不断迭代的前提是算法的持续优化&#xff0c;目前&#xff0c;自动驾驶发展的瓶颈主要在于…

Vue3.0项目实战(二)——大事件管理系统登录注册功能实现

目录 1. 登录注册页面 [element-plus 表单 & 表单校验] 1.1 注册登录 静态结构 & 基本切换 2. 注册功能 2.1 实现注册校验 2.2 注册前的预校验 2.3 封装 api 实现注册功能 3. 登录功能 3.1 实现登录校验 3.2 登录前的预校验 & 登录成功 1. 登录注册页面 […

交换排序(冒泡排序和快速排序)

一、基本思想 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置。 交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 二、冒泡排序 1.核心思想 两两相邻的元素进行比…

大二必做项目贪吃蛇超详解之上篇win32库介绍

文章目录 1. 游戏背景2. 游戏效果演示3. 项目目标4. 前置知识5. Win32 API5. 1 控制台程序(Console)5. 2 控制台屏幕上的坐标 COORD5. 3 GetStdHandle5. 4 GetConsoleCursorlnfo5. 4. 1 CONSOLE_CURSOR_INFO5. 4. 2 SetConsoleCursorlnfo 5. 5 SetconsoleCursorPosition5. 6 Ge…

Linux(面试篇)

目录 什么是Linux 什么是Linux内核&#xff1f; Linux的基本组件是什么&#xff1f; Bash和Dos之间基本区别是什么&#xff1f; 什么是Root账户 什么是Bash? 什么时CLI? Linux的目录结构时怎样的&#xff1f; 什么是硬链接和软链接&#xff1f; 什么叫CC攻击&#…

【项目日记】高并发内存池 ---项目介绍及组件定长池的实现

余生还长&#xff0c;你别慌&#xff0c;也别回头&#xff0c;别念旧. --- 余华 --- 1 高并发内存池简介 高并发内存池项目是实现一个高并发的内存池&#xff0c;他的原型是google的一个开源项目tcmalloc&#xff0c;tcmalloc全称Thread-Caching Malloc&#xff0c;即线程缓存…

RocketMQ Dashboard

rocketmq-dashboard是一个可视化查看和管理RocketMQ消息队列的工具 官方地址&#xff1a;RocketMQ Dashboard | RocketMQ 1、点击下载源码 2、下载并解压&#xff0c;切换至源码目录rocketmq-dashboard-1.0.0 3、修改配置文件 4、编译 rocketmq-dashboard打成jar包 &#xf…

MySQL中的回表查询、索引覆盖、索引下推

本文重点介绍索引中的常见概念&#xff1a;回表查询、索引覆盖、索引下推 一、回表查询 我们首先理解&#xff1a;在InnoDB存储引擎中&#xff0c;根据索引的存储形式&#xff0c;又可以分为以下两种&#xff1a; 分类含义特点聚集索引 (Clustered Index)将数据存储与索引放到…

leetcode 438.找到字符串中所有字母异位词

目录 题目描述 示例1&#xff1a; 示例2&#xff1a; 提示&#xff1a; 解题思路 Collections库 介绍 滑动窗口法 概念 应用场景及特点&#xff1a; 思路 流程展示 代码 复杂度分析 题目描述 给定两个字符串s和p&#xff0c;找到s中所有p的异位词的子串&#xf…

cdga|让数据治理真正内嵌于企业本身,释放企业数字化建设的最大价值

在当今这个数据驱动的时代&#xff0c;企业数据已成为最宝贵的资产之一&#xff0c;它不仅记录着企业的运营轨迹&#xff0c;更是指导决策、优化流程、创新产品与服务的关键力量。然而&#xff0c;要充分发挥数据的潜力&#xff0c;实现数字化转型的深度与广度&#xff0c;就必…

SAP 有趣的‘bug‘ 选择屏幕输入框没了

如下代码将会输出一个P_U的字段 PARAMETERS p_u TYPE string VISIBLE LENGTH 12 MEMORY ID m1.AT SELECTION-SCREEN OUTPUT.LOOP AT SCREEN.IF screen-name P_U.screen-invisible 1.MODIFY SCREEN.ENDIF.ENDLOOP. 如果我们给这个字段设置一个默认值&#xff0c;参考如下代码…

医疗器械法规标准相关资料

文章目录 前言如何查找法规文件与标准1. 法规清单2. 医疗器械法规文件汇编常用链接常见网站微信公众号前言 在前文 医疗器械软件相关法律法规与标准 中介绍了在软件设计过程常见的法规与标准,并给出部分标准如何查找和下载的方法,但是上文中列举的部分不全面,真实在产品设计…

集合及数据结构第十节(上)————优先级队列,堆的创建、插入、删除与用堆模拟实现优先级队列

系列文章目录 集合及数据结构第十节&#xff08;上&#xff09;————优先级队列&#xff0c;堆的创建、插入、删除与用堆模拟实现优先级队列 优先级队列&#xff0c;堆的创建、插入、删除与用堆模拟实现优先级队列 优先级队列的概念堆的概念堆的存储方式堆的创建变量的作…

审计发现 FBI 的数据存储管理存在重大漏洞

据The Hacker News消息&#xff0c;美国司法部监察长办公室 &#xff08;OIG&#xff09; 的一项审计发现&#xff0c; FBI 在库存管理和处置涉及机密数据的电子存储媒体方面存在“重大漏洞”。 OIG 的审计显示&#xff0c;FBI 对包含敏感但未分类 &#xff08;SBU&#xff09…

Nvidia驱动莫名其妙不好使了?nvidia-smi报错?如何解决?已解决!!

文章目录 一、报错提示二、解决方案2.1 原因1的解决办法2.2 原因2的解决方案 一、报错提示 Ubuntu20.04出现Failed to initialize NVML: Driver/library version mismatch问题NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver. 二、解决方案 …

论文翻译:Multi-step Jailbreaking Privacy Attacks on ChatGPT

Multi-step Jailbreaking Privacy Attacks on ChatGPT https://arxiv.org/pdf/2304.05197 多步骤越狱隐私攻击对ChatGPT的影响 文章目录 多步骤越狱隐私攻击对ChatGPT的影响摘要1 引言2 相关工作3 对ChatGPT的数据提取攻击3.1 数据收集3.2 攻击制定3.3 从ChatGPT中提取私人数据…