[PATCH v3 0/1] MR10022: gdiplus: Allow GdipBitmapLockBits without read/write flags.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59362 [Testbot run with this patch](https://testbot.winehq.org/JobDetails.pl?Key=161700) -- v3: gdiplus: Allow GdipBitmapLockBits without read/write flags. https://gitlab.winehq.org/wine/wine/-/merge_requests/10022
From: Bernhard Übelacker <bernhardu@mailbox.org> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59362 --- dlls/gdiplus/image.c | 2 +- dlls/gdiplus/tests/image.c | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 2449e2ec863..035db159d5b 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -1125,7 +1125,7 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect, if(rect){ if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) || - (rect->Y + rect->Height > bitmap->height) || !flags) + (rect->Y + rect->Height > bitmap->height)) { image_unlock(&bitmap->image); return InvalidParameter; diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index e3602ceb505..1f4d3ad8876 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -901,6 +901,48 @@ static void test_LockBits(void) stat = GdipBitmapSetPixel(bm, 2, 8, 0xff480000); expect(Ok, stat); + /* no read/write flags, no conversion */ + stat = GdipBitmapLockBits(bm, &rect, 0, PixelFormat24bppRGB, &bd); + expect(Ok, stat); + + if (stat == Ok) { + expect(0xc3, ((BYTE*)bd.Scan0)[2]); + expect(0x48, ((BYTE*)bd.Scan0)[2 + bd.Stride * 5]); + + ((char*)bd.Scan0)[2] = 0xfd; + + stat = GdipBitmapUnlockBits(bm, &bd); + expect(Ok, stat); + } + + stat = GdipBitmapGetPixel(bm, 2, 3, &color); + expect(Ok, stat); + expect(0xfffd0000, color); + + stat = GdipBitmapSetPixel(bm, 2, 3, 0xffc30000); + expect(Ok, stat); + + /* no read/write flags, conversion */ + stat = GdipBitmapLockBits(bm, &rect, 0, PixelFormat32bppARGB, &bd); + expect(Ok, stat); + + if (stat == Ok) { + /* bits appear to be uninitialized */ + + ((char*)bd.Scan0)[2] = 0xfe; + + stat = GdipBitmapUnlockBits(bm, &bd); + expect(Ok, stat); + } + + /* writes do not work if there was a conversion */ + stat = GdipBitmapGetPixel(bm, 2, 3, &color); + expect(Ok, stat); + expect(0xffc30000, color); + + stat = GdipBitmapSetPixel(bm, 2, 3, 0xffc30000); + expect(Ok, stat); + /* read-only */ stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead, PixelFormat24bppRGB, &bd); expect(Ok, stat); @@ -1142,6 +1184,24 @@ static void test_LockBits_UserBuf(void) bd.Scan0 = &bits[2+3*WIDTH]; bd.Reserved = 0xaaaaaaaa; + /* no read/write flags */ + stat = GdipBitmapLockBits(bm, &rect, ImageLockModeUserInputBuf, PixelFormat32bppARGB, &bd); + expect(Ok, stat); + + expect(0xaaaaaaaa, bits[0]); + expect(0xaaaaaaaa, bits[2+3*WIDTH]); + + bits[2+3*WIDTH] = 0xdeadbeef; + + if (stat == Ok) { + stat = GdipBitmapUnlockBits(bm, &bd); + expect(Ok, stat); + } + + stat = GdipBitmapGetPixel(bm, 2, 3, &color); + expect(Ok, stat); + expect(0, color); + /* read-only */ stat = GdipBitmapLockBits(bm, &rect, ImageLockModeRead|ImageLockModeUserInputBuf, PixelFormat32bppARGB, &bd); expect(Ok, stat); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10022
On Sat Feb 7 14:46:48 2026 +0000, Esme Povirk wrote:
We should also test this while requesting a different pixel format so that a conversion is required. It's possible that it isn't "supposed" to allow writing, but native has an optimization (which we must copy) where it will point the caller directly to the bitmap's buffer, which allows writing even when the flag isn't specified. Thanks for taking a look. I added a conversion to test_LockBits, but to me it looks that neither bits are read from nor wrote back into the bitmap. Is this somewhere near what you had in mind?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10022#note_129018
v2/v3: - Added a case which requires a conversion to test_LockBits. [Testbot run with this patch](https://testbot.winehq.org/JobDetails.pl?Key=161780) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10022#note_129019
On Sat Feb 7 18:11:58 2026 +0000, Bernhard Übelacker wrote:
Thanks for taking a look. I added a conversion to test_LockBits, but to me it looks that neither bits are read from nor wrote back into the bitmap. Is this somewhere near what you had in mind? Yep, this explains native's behavior pretty well: no read/write access is apparently a valid (though seemingly useless) configuration, and the optimization that points callers directly to the bitmap's backing memory effectively converts that to read+write. And that lines up with the fix.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10022#note_129034
This merge request was approved by Esme Povirk. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10022
participants (3)
-
Bernhard Übelacker -
Bernhard Übelacker (@bernhardu) -
Esme Povirk (@madewokherd)