Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ole32/tests/usrmarshal.c | 46 +++++++++++++++ dlls/ole32/usrmarshal.c | 126 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 158 insertions(+), 14 deletions(-)
diff --git a/dlls/ole32/tests/usrmarshal.c b/dlls/ole32/tests/usrmarshal.c index 529ad757c6a..ba62bb08c23 100644 --- a/dlls/ole32/tests/usrmarshal.c +++ b/dlls/ole32/tests/usrmarshal.c @@ -1190,6 +1190,51 @@ static void test_marshal_HBRUSH(void) DeleteObject(hBrush); }
+static void test_marshal_HBITMAP(void) +{ + static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize); + static BYTE bmp_bits[1024]; + MIDL_STUB_MESSAGE stub_msg; + HBITMAP hBitmap, hBitmap2; + USER_MARSHAL_CB umcb; + RPC_MESSAGE rpc_msg; + unsigned char *buffer; + unsigned char bitmap[1024]; + ULONG size, bitmap_size; + + memset(bmp_bits, 0xbb, sizeof(bmp_bits)); + hBitmap = CreateBitmap(16, 16, 1, 1, bmp_bits); + ok(hBitmap != 0, "CreateBitmap failed\n"); + size = GetObjectA(hBitmap, sizeof(bitmap), bitmap); + ok(size != 0, "GetObject failed\n"); + bitmap_size = GetBitmapBits(hBitmap, 0, NULL); + ok(bitmap_size != 0, "GetBitmapBits failed\n"); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + size = HBITMAP_UserSize(&umcb.Flags, 0, &hBitmap); + ok(size == 0xc + header_size + bitmap_size || + broken(size == 0x10 + header_size + bitmap_size), /* Windows adds 4 extra (unused) bytes */ + "Wrong size %d\n", size); + + buffer = HeapAlloc(GetProcessHeap(), 0, size); + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HBITMAP_UserMarshal(&umcb.Flags, buffer, &hBitmap); + ok(*(ULONG *)buffer == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08x\n", *(ULONG *)buffer); + ok(*(ULONG *)(buffer + 0x4) == (ULONG)(ULONG_PTR)hBitmap, "wirestgm + 0x4 should be bitmap handle instead of 0x%08x\n", *(ULONG *)(buffer + 0x4)); + ok(*(ULONG *)(buffer + 0x8) == (ULONG)(ULONG_PTR)bitmap_size, "wirestgm + 0x8 should be bitmap size instead of 0x%08x\n", *(ULONG *)(buffer + 0x4)); + ok(!memcmp(buffer + 0xc, bitmap, header_size), "buffer mismatch\n"); + ok(!memcmp(buffer + 0xc + header_size, bmp_bits, bitmap_size), "buffer mismatch\n"); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_LOCAL); + HBITMAP_UserUnmarshal(&umcb.Flags, buffer, &hBitmap2); + ok(hBitmap2 != NULL, "Didn't unmarshal properly\n"); + HeapFree(GetProcessHeap(), 0, buffer); + + init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_LOCAL); + HBITMAP_UserFree(&umcb.Flags, &hBitmap2); + DeleteObject(hBitmap); +} + struct obj { IDataObject IDataObject_iface; @@ -1353,6 +1398,7 @@ START_TEST(usrmarshal) test_marshal_HDC(); test_marshal_HICON(); test_marshal_HBRUSH(); + test_marshal_HBITMAP();
test_GetDataHere_Proxy();
diff --git a/dlls/ole32/usrmarshal.c b/dlls/ole32/usrmarshal.c index 03ad689f03b..605cdbc1822 100644 --- a/dlls/ole32/usrmarshal.c +++ b/dlls/ole32/usrmarshal.c @@ -586,8 +586,26 @@ void __RPC_USER HGLOBAL_UserFree(ULONG *pFlags, HGLOBAL *phGlobal) */ ULONG __RPC_USER HBITMAP_UserSize(ULONG *pFlags, ULONG StartingSize, HBITMAP *phBmp) { - FIXME(":stub\n"); - return StartingSize; + ULONG size = StartingSize; + + TRACE("(%s, %d, %p)\n", debugstr_user_flags(pFlags), StartingSize, *phBmp); + + size += sizeof(ULONG); + if (LOWORD(*pFlags) == MSHCTX_INPROC) + size += sizeof(ULONG_PTR); + else + { + size += sizeof(ULONG); + + if (*phBmp) + { + size += sizeof(ULONG); + size += FIELD_OFFSET(userBITMAP, cbSize); + size += GetBitmapBits(*phBmp, 0, NULL); + } + } + + return size; }
/****************************************************************************** @@ -611,7 +629,43 @@ ULONG __RPC_USER HBITMAP_UserSize(ULONG *pFlags, ULONG StartingSize, HBITMAP *ph */ unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) { - FIXME(":stub\n"); + TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, *phBmp); + + if (LOWORD(*pFlags) == MSHCTX_INPROC) + { + if (sizeof(*phBmp) == 8) + *(ULONG *)pBuffer = WDT_INPROC64_CALL; + else + *(ULONG *)pBuffer = WDT_INPROC_CALL; + pBuffer += sizeof(ULONG); + *(HBITMAP *)pBuffer = *phBmp; + pBuffer += sizeof(HBITMAP); + } + else + { + *(ULONG *)pBuffer = WDT_REMOTE_CALL; + pBuffer += sizeof(ULONG); + *(ULONG *)pBuffer = (ULONG)(ULONG_PTR)*phBmp; + pBuffer += sizeof(ULONG); + + if (*phBmp) + { + static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize); + BITMAP bitmap; + ULONG bitmap_size; + + bitmap_size = GetBitmapBits(*phBmp, 0, NULL); + *(ULONG *)pBuffer = bitmap_size; + pBuffer += sizeof(ULONG); + + GetObjectW(*phBmp, sizeof(BITMAP), &bitmap); + memcpy(pBuffer, &bitmap, header_size); + pBuffer += header_size; + + GetBitmapBits(*phBmp, bitmap_size, pBuffer); + pBuffer += bitmap_size; + } + } return pBuffer; }
@@ -636,7 +690,54 @@ unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *pFlags, unsigned char *pBu */ unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HBITMAP *phBmp) { - FIXME(":stub\n"); + ULONG fContext; + + TRACE("(%s, %p, %p)\n", debugstr_user_flags(pFlags), pBuffer, phBmp); + + fContext = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if (((fContext == WDT_INPROC_CALL) && (sizeof(*phBmp) < 8)) || + ((fContext == WDT_INPROC64_CALL) && (sizeof(*phBmp) == 8))) + { + *phBmp = *(HBITMAP *)pBuffer; + pBuffer += sizeof(*phBmp); + } + else if (fContext == WDT_REMOTE_CALL) + { + ULONG handle; + + handle = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + + if (handle) + { + static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize); + BITMAP bitmap; + ULONG bitmap_size; + unsigned char *bits; + + bitmap_size = *(ULONG *)pBuffer; + pBuffer += sizeof(ULONG); + bits = HeapAlloc(GetProcessHeap(), 0, bitmap_size); + + memcpy(&bitmap, pBuffer, header_size); + pBuffer += header_size; + + memcpy(bits, pBuffer, bitmap_size); + pBuffer += bitmap_size; + + bitmap.bmBits = bits; + *phBmp = CreateBitmapIndirect(&bitmap); + + HeapFree(GetProcessHeap(), 0, bits); + } + else + *phBmp = NULL; + } + else + RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL); + return pBuffer; }
@@ -660,7 +761,10 @@ unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *pFlags, unsigned char *p */ void __RPC_USER HBITMAP_UserFree(ULONG *pFlags, HBITMAP *phBmp) { - FIXME(":stub\n"); + TRACE("(%s, %p)\n", debugstr_user_flags(pFlags), *phBmp); + + if (LOWORD(*pFlags) != MSHCTX_INPROC) + DeleteObject(*phBmp); }
/****************************************************************************** @@ -1620,9 +1724,7 @@ ULONG __RPC_USER STGMEDIUM_UserSize(ULONG *pFlags, ULONG StartingSize, STGMEDIUM case TYMED_GDI: TRACE("TYMED_GDI\n"); if (pStgMedium->u.hBitmap) - { - FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap); - } + size = HBITMAP_UserSize(pFlags, size, &pStgMedium->u.hBitmap); break; case TYMED_MFPICT: TRACE("TYMED_MFPICT\n"); @@ -1732,9 +1834,7 @@ unsigned char * __RPC_USER STGMEDIUM_UserMarshal(ULONG *pFlags, unsigned char *p case TYMED_GDI: TRACE("TYMED_GDI\n"); if (pStgMedium->u.hBitmap) - { - FIXME("not implemented for GDI object %p\n", pStgMedium->u.hBitmap); - } + pBuffer = HBITMAP_UserMarshal(pFlags, pBuffer, &pStgMedium->u.hBitmap); break; case TYMED_MFPICT: TRACE("TYMED_MFPICT\n"); @@ -1870,9 +1970,7 @@ unsigned char * __RPC_USER STGMEDIUM_UserUnmarshal(ULONG *pFlags, unsigned char case TYMED_GDI: TRACE("TYMED_GDI\n"); if (content) - { - FIXME("not implemented for GDI object\n"); - } + pBuffer = HBITMAP_UserUnmarshal(pFlags, pBuffer, &pStgMedium->u.hBitmap); else pStgMedium->u.hBitmap = NULL; break;