GDI/GDI+截图转JPG后,如何获取TCP传输所需的字节数组?
从GDI+的IStream中提取JPG字节数组用于TCP传输
你现在的代码已经通过CreateStreamOnHGlobal创建了内存流并把JPG数据写入其中,但还没把流内的内容转换成可用于TCP传输的字节数组。下面是具体的实现步骤和修正后的完整代码:
关键问题修正
- 删掉
delete &clsid;——clsid是栈上的局部变量,不能用delete释放,属于错误操作。 - 调整GDI资源释放顺序:必须先恢复DC中的旧位图,再销毁位图和DC,避免资源泄漏。
- 从
IStream提取字节数据需要借助它绑定的HGLOBAL内存块来获取指针和数据长度。
修正后的完整代码
#include <Gdiplus.h> #include <windows.h> #include <iostream> #pragma comment(lib, "Gdiplus.lib") void screenshot() { using namespace Gdiplus; IStream* istream = nullptr; HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream); if (FAILED(res)) { return; } GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); { HDC scrdc = ::GetDC(0); if (!scrdc) { goto Cleanup; } int Height = GetSystemMetrics(SM_CYSCREEN); int Width = GetSystemMetrics(SM_CXSCREEN); HDC memdc = CreateCompatibleDC(scrdc); HBITMAP membit = CreateCompatibleBitmap(scrdc, Width, Height); if (!memdc || !membit) { goto CleanupDC; } HBITMAP hOldBitmap = (HBITMAP)SelectObject(memdc, membit); BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY); Gdiplus::Bitmap bitmap(membit, NULL); CLSID clsid; GetEncoderClsid(L"image/jpeg", &clsid); // 将JPG数据写入内存流 bitmap.Save(istream, &clsid, NULL); // 提取JPG字节数组的核心逻辑 HGLOBAL hGlobal = NULL; if (SUCCEEDED(GetHGlobalFromStream(istream, &hGlobal))) { BYTE* pJpgBuffer = (BYTE*)GlobalLock(hGlobal); DWORD bufferSize = GlobalSize(hGlobal); // pJpgBuffer就是JPG原始字节数据,bufferSize是数据总长度 // 转成char*直接用于TCP传输: char* tcpBuffer = reinterpret_cast<char*>(pJpgBuffer); // 示例:打印数据长度(替换成你的TCP发送逻辑即可) std::cout << "JPG数据字节数:" << bufferSize << std::endl; // 使用完必须解锁内存块 GlobalUnlock(hGlobal); } // 正确释放GDI资源 SelectObject(memdc, hOldBitmap); DeleteObject(membit); DeleteDC(memdc); CleanupDC: ::ReleaseDC(0, scrdc); } Cleanup: GdiplusShutdown(gdiplusToken); if (istream) { istream->Release(); } }
核心提取逻辑说明
GetHGlobalFromStream:获取IStream背后绑定的HGLOBAL内存句柄。GlobalLock:锁定内存块,返回的指针就是JPG数据的起始地址。GlobalSize:获取内存块的总字节数,也就是JPG数据的长度。- 把
BYTE*强制转成char*后,就可以直接传入TCP的send等传输函数使用。 - 必须调用
GlobalUnlock解锁内存块,避免资源泄漏。
内容的提问来源于stack exchange,提问作者user21806805
相关产品推荐
相关产品推荐

