Access数据库位图文件数据的读写(二)

从数据库读取数据到VARIANT结构中

VARIANT varVal;
VariantInit(&varVal);

//注意要通过get_value()才能读取数据到VARIANT结构中
rs->GetFields()->GetItem(TEXT("ImgData"))->get_Value(&varVal);

把VARIANT数据转为HBITMAP位图句柄

HBITMAP QAdo::VariantToHBitmap(VARIANT& varVal) {
    SAFEARRAY* psa = nullptr;
    void* pData = nullptr;
    HRESULT hr = S_OK;
    long ugSize=0, dataSize = 0;
    HBITMAP hBitmap = 0;

    if (V_VT(&varVal) & VT_ARRAY) {
        psa = V_ARRAY(&varVal);

        //3.访问safeArry数据
        hr = SafeArrayAccessData(psa, &pData);
        assert(hr == S_OK);

        SafeArrayGetUBound(psa, 1, &ugSize);
        //SafeArrayGetLBound(psa, 1, &lgSize);
        dataSize = SafeArrayGetElemsize(psa)*ugSize + 1;
        

        BYTE* pBuffer = (BYTE*)malloc(dataSize);
        memcpy(pBuffer, pData, dataSize);

        hBitmap = CreateBitmapFromMemory((unsigned char*)pBuffer, dataSize);
        //assert(hBitmap);

        if(pBuffer)
            free(pBuffer);

    }

    VariantClear(&varVal);

    return hBitmap;
}

HBITMAP g_hBitmap=ado.VariantToHBitmap(varVal);

CreateBitmapFromMemory 函数的实现

/*
    通过二进制数组创建位图
    参数:
        pData    二进制数组(BYTE*)
        dataSize    数组大小
    返回:
        位图句柄
*/
HBITMAP QAdo::CreateBitmapFromMemory(const unsigned char* pData, DWORD dataSize)
{
    if (!pData || dataSize == 0) return NULL;

    // 1. 解析 BMP 文件头
    BITMAPFILEHEADER* pFileHeader = (BITMAPFILEHEADER*)pData;

    // 验证是否是合法的 BMP 文件 ('BM')
    if (pFileHeader->bfType != 0x4D42) {
        return NULL;
    }

    // 2. 获取位图信息头 (BITMAPINFOHEADER)
    // 它紧跟在文件头之后
    BITMAPINFOHEADER* pInfoHeader = (BITMAPINFOHEADER*)(pData + sizeof(BITMAPFILEHEADER));

    // 3. 计算像素数据的偏移量
    // bfOffBits 指定了从文件开头到像素数据的字节偏移
    DWORD pixelOffset = pFileHeader->bfOffBits;

    // 确保偏移量合法
    if (pixelOffset >= dataSize) return NULL;

    const void* pPixelData = (const void*)(pData + pixelOffset);

    // 4. 创建兼容 DC
    HDC hScreenDC = GetDC(NULL); // 获取屏幕 DC
    HDC hMemDC = CreateCompatibleDC(hScreenDC);

    // 5. 创建 DIB Section
    // DIB Section 允许我们直接操作位图内存,或者让 GDI 管理它
    HBITMAP hBitmap = CreateDIBSection(
        hMemDC,
        (BITMAPINFO*)pInfoHeader, // 注意:BITMAPINFOHEADER 是 BITMAPINFO 的一部分
        DIB_RGB_COLORS,
        NULL,   // 不需要返回内存指针,因为数据已经在 pData 中
        NULL,
        0
    );

    if (hBitmap) {
        // 6. 将数据库中的像素数据拷贝到 HBITMAP 中
        // SetDIBits 会自动处理行对齐和格式转换
        int lines = SetDIBits(
            hMemDC,
            hBitmap,
            0,                          // 起始扫描线
            pInfoHeader->biHeight,      // 扫描线数量
            pPixelData,                 // 源像素数据
            (BITMAPINFO*)pInfoHeader,   // 位图信息
            DIB_RGB_COLORS
        );

        if (lines == 0) {
            DeleteObject(hBitmap);
            hBitmap = NULL;
        }
    }

    // 清理临时 DC
    DeleteDC(hMemDC);
    ReleaseDC(NULL, hScreenDC);

    return hBitmap;
}

用位图句柄绘制到窗口上

case WM_PAINT: {
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hwnd, &ps);

	if (g_hBitmap) {
		// 在窗口坐标 (10, 10) 处绘制图片
		DrawBitmapToWindow(hdc, g_hBitmap, 10, 10);
	}
	else {
		TextOut(hdc, 10, 10, L"No Image Loaded", 13);
	}

	EndPaint(hwnd, &ps);
	break;
}

  

效果呈现

image

 

 
posted @ 2026-06-11 10:18  初吻给了烟灬  阅读(3)  评论(0)    收藏  举报