From 1b3f66703f990b8bb081f190d44bdd7102edfe0c Mon Sep 17 00:00:00 2001 From: Robinson Date: Sun, 7 Feb 2021 00:14:43 +0100 Subject: [PATCH] More cautious image creation --- src/dorkbox/jna/windows/HBITMAPWrap.java | 90 +++++++++++++----------- src/dorkbox/jna/windows/HICONWrap.java | 10 ++- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/dorkbox/jna/windows/HBITMAPWrap.java b/src/dorkbox/jna/windows/HBITMAPWrap.java index 3a3955e..52a6f2c 100644 --- a/src/dorkbox/jna/windows/HBITMAPWrap.java +++ b/src/dorkbox/jna/windows/HBITMAPWrap.java @@ -34,6 +34,8 @@ import com.sun.jna.ptr.PointerByReference; public class HBITMAPWrap extends HBITMAP { + private static final Object lockObject = new Object(); + // NOTE: This is a field (instead of private) so that GC does not try to collect this object private HBITMAP bitmap; @@ -42,54 +44,58 @@ public class HBITMAPWrap extends HBITMAP { HBITMAP createBitmap(BufferedImage image) { int w = image.getWidth(null); int h = image.getHeight(null); - HDC screenDC = User32.GetDC(null); - HDC memDC = GDI32.CreateCompatibleDC(screenDC); - HBITMAP hBitmap = null; - try { - BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); - Graphics2D g = (Graphics2D) buf.getGraphics(); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g.drawImage(image, 0, 0, w, h, null); + // all sorts of issues occur if this is called quickly from different threads! + synchronized(lockObject) { + HDC screenDC = User32.GetDC(null); + HDC memDC = GDI32.CreateCompatibleDC(screenDC); + HBITMAP hBitmap = null; - WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO(); - bmi.bmiHeader.biWidth = w; - bmi.bmiHeader.biHeight = h; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = WinGDI.BI_RGB; - bmi.bmiHeader.biSizeImage = w * h * 4; + try { + BufferedImage buf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); + Graphics2D g = (Graphics2D) buf.getGraphics(); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + g.drawImage(image, 0, 0, w, h, null); - Memory memory = new Memory(w*h*32*4); - PointerByReference pointerRef = new PointerByReference(memory); - hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0); - Pointer pointerToBits = pointerRef.getValue(); + WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO(); + bmi.bmiHeader.biWidth = w; + bmi.bmiHeader.biHeight = h; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = WinGDI.BI_RGB; + bmi.bmiHeader.biSizeImage = w * h * 4; - if (pointerToBits == null) { - // the bitmap was invalid - LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage()); - } - else { - Raster raster = buf.getData(); - int[] pixel = new int[4]; - int[] bits = new int[w * h]; - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - raster.getPixel(x, h - y - 1, pixel); - int red = (pixel[2] & 0xFF) << 0; - int green = (pixel[1] & 0xFF) << 8; - int blue = (pixel[0] & 0xFF) << 16; - int alpha = (pixel[3] & 0xFF) << 24; - bits[x + y * w] = alpha | red | green | blue; - } + Memory memory = new Memory(w*h*32*4); + PointerByReference pointerRef = new PointerByReference(memory); + hBitmap = GDI32.CreateDIBSection(memDC, bmi, WinGDI.DIB_RGB_COLORS, pointerRef, null, 0); + Pointer pointerToBits = pointerRef.getValue(); + + if (pointerToBits == null) { + // the bitmap was invalid + LoggerFactory.getLogger(HBITMAPWrap.class).error("The image was invalid", Kernel32Util.getLastErrorMessage()); + } + else { + Raster raster = buf.getData(); + int[] pixel = new int[4]; + int[] bits = new int[w * h]; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + raster.getPixel(x, h - y - 1, pixel); + int red = (pixel[2] & 0xFF) << 0; + int green = (pixel[1] & 0xFF) << 8; + int blue = (pixel[0] & 0xFF) << 16; + int alpha = (pixel[3] & 0xFF) << 24; + bits[x + y * w] = alpha | red | green | blue; + } + } + pointerToBits.write(0, bits, 0, bits.length); } - pointerToBits.write(0, bits, 0, bits.length); - } - return hBitmap; - } finally { - User32.ReleaseDC(null, screenDC); - GDI32.DeleteDC(memDC); + return hBitmap; + } finally { + User32.ReleaseDC(null, screenDC); + GDI32.DeleteDC(memDC); + } } } diff --git a/src/dorkbox/jna/windows/HICONWrap.java b/src/dorkbox/jna/windows/HICONWrap.java index 4f4521e..867e0e3 100644 --- a/src/dorkbox/jna/windows/HICONWrap.java +++ b/src/dorkbox/jna/windows/HICONWrap.java @@ -27,6 +27,7 @@ import dorkbox.jna.windows.structs.ICONINFO; * http://www.pinvoke.net/default.aspx/user32.createiconindirect */ public class HICONWrap extends HICON { + private static final Object lockObject = new Object(); static HICON createIconIndirect(HBITMAP bm) { ICONINFO info = new ICONINFO(); @@ -36,7 +37,14 @@ public class HICONWrap extends HICON { HICON hicon = User32.CreateIconIndirect(info); if (hicon == null) { - throw new GetLastErrorException(); + // something weird is going on! Try again but more carefully! + synchronized(lockObject) { + hicon = User32.CreateIconIndirect(info); + } + + if (hicon == null) { + throw new GetLastErrorException(); + } } return hicon;