BOOL gdi_init_primary(rdpGdi* gdi) { gdi->primary = (gdiBitmap*) calloc(1, sizeof(gdiBitmap)); if (!gdi->primary) goto fail_primary; if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc))) goto fail_hdc; if (!gdi->primary_buffer) gdi->primary->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, gdi->width, gdi->height); else gdi->primary->bitmap = gdi_CreateBitmapEx(gdi->width, gdi->height, gdi->dstBpp, gdi->primary_buffer, NULL); if (!gdi->primary->bitmap) goto fail_bitmap; gdi_SelectObject(gdi->primary->hdc, (HGDIOBJECT) gdi->primary->bitmap); gdi->primary->org_bitmap = NULL; gdi->primary_buffer = gdi->primary->bitmap->data; if (!(gdi->primary->hdc->hwnd = (HGDI_WND) calloc(1, sizeof(GDI_WND)))) goto fail_hwnd; if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0))) goto fail_hwnd; gdi->primary->hdc->hwnd->invalid->null = 1; gdi->primary->hdc->hwnd->count = 32; if (!(gdi->primary->hdc->hwnd->cinvalid = (HGDI_RGN) calloc(gdi->primary->hdc->hwnd->count, sizeof(GDI_RGN)))) goto fail_hwnd; gdi->primary->hdc->hwnd->ninvalid = 0; if (!gdi->drawing) gdi->drawing = gdi->primary; return TRUE; fail_hwnd: gdi_DeleteObject((HGDIOBJECT) gdi->primary->bitmap); fail_bitmap: gdi_DeleteDC(gdi->primary->hdc); fail_hdc: free(gdi->primary); gdi->primary = NULL; fail_primary: return FALSE; }
static BOOL gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { const rdpBrush* brush = &patblt->brush; UINT32 foreColor; UINT32 backColor; UINT32 originalColor; HGDI_BRUSH originalBrush, hbrush = NULL; rdpGdi* gdi = context->gdi; BOOL ret = FALSE; const DWORD rop = gdi_rop3_code(patblt->bRop); UINT32 nXSrc = 0; UINT32 nYSrc = 0; BYTE data[8 * 8 * 4]; HGDI_BITMAP hBmp = NULL; if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL)) return FALSE; if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL)) return FALSE; originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor); originalBrush = gdi->drawing->hdc->brush; switch (brush->style) { case GDI_BS_SOLID: hbrush = gdi_CreateSolidBrush(foreColor); break; case GDI_BS_HATCHED: { const BYTE* hatched; hatched = GDI_BS_HATCHED_PATTERNS + (8 * brush->hatch); if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8, hatched, backColor, foreColor, &gdi->palette)) goto out_error; hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL); if (!hBmp) goto out_error; hbrush = gdi_CreateHatchBrush(hBmp); } break; case GDI_BS_PATTERN: { UINT32 brushFormat; if (brush->bpp > 1) { brushFormat = gdi_get_pixel_format(brush->bpp); if (!freerdp_image_copy(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8, brush->data, brushFormat, 0, 0, 0, &gdi->palette, FREERDP_FLIP_NONE)) goto out_error; } else { if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8, brush->data, backColor, foreColor, &gdi->palette)) goto out_error; } hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL); if (!hBmp) goto out_error; hbrush = gdi_CreatePatternBrush(hBmp); } break; default: WLog_ERR(TAG, "unimplemented brush style:%"PRIu32"", brush->style); break; } if (!hbrush) gdi_DeleteObject((HGDIOBJECT) hBmp); else { hbrush->nXOrg = brush->x; hbrush->nYOrg = brush->y; gdi->drawing->hdc->brush = hbrush; ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette); } out_error: gdi_DeleteObject((HGDIOBJECT) hbrush); gdi->drawing->hdc->brush = originalBrush; gdi_SetTextColor(gdi->drawing->hdc, originalColor); return ret; }
static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer, void (*pfree)(void*)) { gdi->primary = (gdiBitmap*) calloc(1, sizeof(gdiBitmap)); if (format > 0) gdi->dstFormat = format; if (stride > 0) gdi->stride = stride; else gdi->stride = gdi->width * GetBytesPerPixel(gdi->dstFormat); if (!gdi->primary) goto fail_primary; if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc))) goto fail_hdc; if (!buffer) { gdi->primary->bitmap = gdi_CreateCompatibleBitmap( gdi->hdc, gdi->width, gdi->height); } else { gdi->primary->bitmap = gdi_CreateBitmapEx(gdi->width, gdi->height, gdi->dstFormat, gdi->stride, buffer, pfree); } gdi->stride = gdi->primary->bitmap->scanline; if (!gdi->primary->bitmap) goto fail_bitmap; gdi_SelectObject(gdi->primary->hdc, (HGDIOBJECT) gdi->primary->bitmap); gdi->primary->org_bitmap = NULL; gdi->primary_buffer = gdi->primary->bitmap->data; if (!(gdi->primary->hdc->hwnd = (HGDI_WND) calloc(1, sizeof(GDI_WND)))) goto fail_hwnd; if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0))) goto fail_hwnd; gdi->primary->hdc->hwnd->invalid->null = TRUE; gdi->primary->hdc->hwnd->count = 32; if (!(gdi->primary->hdc->hwnd->cinvalid = (HGDI_RGN) calloc( gdi->primary->hdc->hwnd->count, sizeof(GDI_RGN)))) goto fail_hwnd; gdi->primary->hdc->hwnd->ninvalid = 0; if (!gdi->drawing) gdi->drawing = gdi->primary; return TRUE; fail_hwnd: gdi_DeleteObject((HGDIOBJECT) gdi->primary->bitmap); fail_bitmap: gdi_DeleteDC(gdi->primary->hdc); fail_hdc: free(gdi->primary); gdi->primary = NULL; fail_primary: return FALSE; }
int test_gdi_InvalidateRegion(void) { HGDI_DC hdc; HGDI_RGN rgn1; HGDI_RGN rgn2; HGDI_RGN invalid; HGDI_BITMAP bmp; if (!(hdc = gdi_GetDC())) { printf("failed to get gdi device context\n"); return -1; } hdc->bytesPerPixel = 4; hdc->bitsPerPixel = 32; bmp = gdi_CreateBitmapEx(1024, 768, 4, NULL, NULL); gdi_SelectObject(hdc, (HGDIOBJECT) bmp); gdi_SetNullClipRgn(hdc); hdc->hwnd = (HGDI_WND) calloc(1, sizeof(GDI_WND)); hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0); hdc->hwnd->invalid->null = 1; invalid = hdc->hwnd->invalid; hdc->hwnd->count = 16; hdc->hwnd->cinvalid = (HGDI_RGN) calloc(hdc->hwnd->count, sizeof(GDI_RGN)); rgn1 = gdi_CreateRectRgn(0, 0, 0, 0); rgn2 = gdi_CreateRectRgn(0, 0, 0, 0); rgn1->null = 1; rgn2->null = 1; /* no previous invalid region */ invalid->null = 1; gdi_SetRgn(rgn1, 300, 300, 100, 100); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* region same as invalid region */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 100, 100); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* left outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 300, 300, 100); gdi_SetRgn(rgn2, 100, 300, 300, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* right outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 300, 100); gdi_SetRgn(rgn2, 300, 300, 300, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* top outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 100, 100, 300); gdi_SetRgn(rgn2, 300, 100, 100, 300); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* bottom outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 100, 300); gdi_SetRgn(rgn2, 300, 300, 100, 300); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* left outside, right outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 300, 600, 300); gdi_SetRgn(rgn2, 100, 300, 600, 300); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* top outside, bottom outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 100, 100, 500); gdi_SetRgn(rgn2, 300, 100, 100, 500); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* all outside, left */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 300, 100, 100); gdi_SetRgn(rgn2, 100, 300, 300, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* all outside, right */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 700, 300, 100, 100); gdi_SetRgn(rgn2, 300, 300, 500, 100); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* all outside, top */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 100, 100, 100); gdi_SetRgn(rgn2, 300, 100, 100, 300); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* all outside, bottom */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 500, 100, 100); gdi_SetRgn(rgn2, 300, 300, 100, 300); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* all outside */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 100, 600, 600); gdi_SetRgn(rgn2, 100, 100, 600, 600); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; /* everything */ gdi_SetRgn(invalid, 300, 300, 100, 100); gdi_SetRgn(rgn1, 0, 0, 1024, 768); gdi_SetRgn(rgn2, 0, 0, 1024, 768); gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h); if (!gdi_EqualRgn(invalid, rgn2)) return -1; return 0; }
int test_gdi_ClipCoords(void) { BOOL draw; HGDI_DC hdc; HGDI_RGN rgn1; HGDI_RGN rgn2; HGDI_BITMAP bmp; if (!(hdc = gdi_GetDC())) { printf("failed to get gdi device context\n"); return -1; } hdc->bytesPerPixel = 4; hdc->bitsPerPixel = 32; bmp = gdi_CreateBitmapEx(1024, 768, 4, NULL, NULL); gdi_SelectObject(hdc, (HGDIOBJECT) bmp); gdi_SetNullClipRgn(hdc); rgn1 = gdi_CreateRectRgn(0, 0, 0, 0); rgn2 = gdi_CreateRectRgn(0, 0, 0, 0); rgn1->null = 1; rgn2->null = 1; /* null clipping region */ gdi_SetNullClipRgn(hdc); gdi_SetRgn(rgn1, 20, 20, 100, 100); gdi_SetRgn(rgn2, 20, 20, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* region all inside clipping region */ gdi_SetClipRgn(hdc, 0, 0, 1024, 768); gdi_SetRgn(rgn1, 20, 20, 100, 100); gdi_SetRgn(rgn2, 20, 20, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* region all outside clipping region, on the left */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 20, 20, 100, 100); gdi_SetRgn(rgn2, 0, 0, 0, 0); draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (draw) return -1; /* region all outside clipping region, on the right */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 420, 420, 100, 100); gdi_SetRgn(rgn2, 0, 0, 0, 0); draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (draw) return -1; /* region all outside clipping region, on top */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 20, 100, 100); gdi_SetRgn(rgn2, 0, 0, 0, 0); draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (draw) return -1; /* region all outside clipping region, at the bottom */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 420, 100, 100); gdi_SetRgn(rgn2, 0, 0, 0, 0); draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (draw) return -1; /* left outside, right = clip, top = clip, bottom = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 300, 300, 100); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* left outside, right inside, top = clip, bottom = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 100, 300, 250, 100); gdi_SetRgn(rgn2, 300, 300, 50, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* left = clip, right outside, top = clip, bottom = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 300, 100); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* left inside, right outside, top = clip, bottom = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 350, 300, 200, 100); gdi_SetRgn(rgn2, 350, 300, 50, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* top outside, bottom = clip, left = clip, right = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 100, 300, 300); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* top = clip, bottom outside, left = clip, right = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 100, 200); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; /* top = clip, bottom = clip, top = clip, bottom = clip */ gdi_SetClipRgn(hdc, 300, 300, 100, 100); gdi_SetRgn(rgn1, 300, 300, 100, 100); gdi_SetRgn(rgn2, 300, 300, 100, 100); gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL); if (!gdi_EqualRgn(rgn1, rgn2)) return -1; return 0; }
HGDI_BITMAP gdi_CreateBitmap(UINT32 nWidth, UINT32 nHeight, UINT32 format, BYTE* data) { return gdi_CreateBitmapEx(nWidth, nHeight, format, 0, data, _aligned_free); }
static BOOL gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd) { int i, j; int tx, ty; BYTE* pSrcData; BYTE* pDstData; RFX_MESSAGE* message; rdpGdi* gdi = context->gdi; DEBUG_GDI("destLeft %d destTop %d destRight %d destBottom %d " "bpp %d codecID %d width %d height %d length %d", cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bpp, cmd->codecID, cmd->width, cmd->height, cmd->bitmapDataLength); if (cmd->codecID == RDP_CODEC_ID_REMOTEFX) { if (!freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX)) return FALSE; if (!(message = rfx_process_message(gdi->codecs->rfx, cmd->bitmapData, cmd->bitmapDataLength))) { WLog_ERR(TAG, "Failed to process RemoteFX message"); return FALSE; } /* blit each tile */ for (i = 0; i < message->numTiles; i++) { tx = message->tiles[i]->x + cmd->destLeft; ty = message->tiles[i]->y + cmd->destTop; pSrcData = message->tiles[i]->data; pDstData = gdi->tile->bitmap->data; if (!gdi->invert && (gdi->dstBpp == 32)) { gdi->tile->bitmap->data = pSrcData; } else { freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, 64, 64, pSrcData, PIXEL_FORMAT_XRGB32, -1, 0, 0, gdi->palette); } for (j = 0; j < message->numRects; j++) { gdi_SetClipRgn(gdi->primary->hdc, cmd->destLeft + message->rects[j].x, cmd->destTop + message->rects[j].y, message->rects[j].width, message->rects[j].height); gdi_BitBlt(gdi->primary->hdc, tx, ty, 64, 64, gdi->tile->hdc, 0, 0, GDI_SRCCOPY); } gdi->tile->bitmap->data = pDstData; } gdi_SetNullClipRgn(gdi->primary->hdc); rfx_message_free(gdi->codecs->rfx, message); } else if (cmd->codecID == RDP_CODEC_ID_NSCODEC) { if (!freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_NSCODEC)) return FALSE; nsc_process_message(gdi->codecs->nsc, cmd->bpp, cmd->width, cmd->height, cmd->bitmapData, cmd->bitmapDataLength); if (gdi->bitmap_size < (cmd->width * cmd->height * 4)) { gdi->bitmap_size = cmd->width * cmd->height * 4; gdi->bitmap_buffer = (BYTE*) _aligned_realloc(gdi->bitmap_buffer, gdi->bitmap_size, 16); if (!gdi->bitmap_buffer) return FALSE; } pDstData = gdi->bitmap_buffer; pSrcData = gdi->codecs->nsc->BitmapData; freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, gdi->palette); gdi_DeleteObject((HGDIOBJECT)gdi->image->bitmap); gdi->image->bitmap = gdi_CreateBitmapEx(cmd->width, cmd->height, cmd->bpp, gdi->bitmap_buffer, NULL); gdi_SelectObject(gdi->image->hdc, (HGDIOBJECT) gdi->image->bitmap); gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } else if (cmd->codecID == RDP_CODEC_ID_NONE) { if (gdi->bitmap_size < (cmd->width * cmd->height * 4)) { gdi->bitmap_size = cmd->width * cmd->height * 4; gdi->bitmap_buffer = (BYTE*) _aligned_realloc(gdi->bitmap_buffer, gdi->bitmap_size, 16); if (!gdi->bitmap_buffer) return FALSE; } pDstData = gdi->bitmap_buffer; pSrcData = cmd->bitmapData; freerdp_image_copy(pDstData, gdi->format, -1, 0, 0, cmd->width, cmd->height, pSrcData, PIXEL_FORMAT_XRGB32_VF, -1, 0, 0, gdi->palette); gdi_DeleteObject((HGDIOBJECT)gdi->image->bitmap); gdi->image->bitmap = gdi_CreateBitmapEx(cmd->width, cmd->height, cmd->bpp, gdi->bitmap_buffer, NULL); gdi_SelectObject(gdi->image->hdc, (HGDIOBJECT) gdi->image->bitmap); gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } else { WLog_ERR(TAG, "Unsupported codecID %d", cmd->codecID); } return TRUE; }