diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 7ac305c878..b5dd25e685 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -69,6 +69,25 @@ void* getUser32Function (const char*); extern HWND juce_messageWindowHandle; #endif +struct ScopedDeviceContext +{ + explicit ScopedDeviceContext (HWND h) + : hwnd (h), dc (GetDC (hwnd)) + { + } + + ~ScopedDeviceContext() + { + ReleaseDC (hwnd, dc); + } + + HWND hwnd; + HDC dc; + + JUCE_DECLARE_NON_COPYABLE (ScopedDeviceContext) + JUCE_DECLARE_NON_MOVEABLE (ScopedDeviceContext) +}; + //============================================================================== #ifndef WM_TOUCH enum @@ -475,10 +494,8 @@ static double getGlobalDPI() { setDPIAwareness(); - HDC dc = GetDC (nullptr); - auto dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0; - ReleaseDC (nullptr, dc); - return dpi; + ScopedDeviceContext deviceContext { nullptr }; + return (GetDeviceCaps (deviceContext.dc, LOGPIXELSX) + GetDeviceCaps (deviceContext.dc, LOGPIXELSY)) / 2.0; } //============================================================================== @@ -847,9 +864,10 @@ public: bitmapInfo.bV4V4Compression = BI_RGB; } - HDC dc = GetDC (nullptr); - hdc = CreateCompatibleDC (dc); - ReleaseDC (nullptr, dc); + { + ScopedDeviceContext deviceContext { nullptr }; + hdc = CreateCompatibleDC (deviceContext.dc); + } SetMapMode (hdc, MM_TEXT); @@ -942,10 +960,8 @@ public: private: static bool isGraphicsCard32Bit() { - auto dc = GetDC (nullptr); - auto bitsPerPixel = GetDeviceCaps (dc, BITSPIXEL); - ReleaseDC (nullptr, dc); - return bitsPerPixel > 24; + ScopedDeviceContext deviceContext { nullptr }; + return GetDeviceCaps (deviceContext.dc, BITSPIXEL) > 24; } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage) @@ -964,7 +980,7 @@ Image createSnapshotOfNativeWindow (void* nativeWindowHandle) auto nativeBitmap = new WindowsBitmapImage (Image::RGB, w, h, true); Image bitmap (nativeBitmap); - HDC dc = GetDC (hwnd); + ScopedDeviceContext deviceContext { hwnd }; if (isPerMonitorDPIAwareProcess()) { @@ -973,18 +989,16 @@ Image createSnapshotOfNativeWindow (void* nativeWindowHandle) SetBrushOrgEx (nativeBitmap->hdc, 0, 0, NULL); StretchBlt (nativeBitmap->hdc, 0, 0, w, h, - dc, 0, 0, roundToInt (w * scale), roundToInt (h * scale), + deviceContext.dc, 0, 0, roundToInt (w * scale), roundToInt (h * scale), SRCCOPY); SetStretchBltMode (nativeBitmap->hdc, prevStretchMode); } else { - BitBlt (nativeBitmap->hdc, 0, 0, w, h, dc, 0, 0, SRCCOPY); + BitBlt (nativeBitmap->hdc, 0, 0, w, h, deviceContext.dc, 0, 0, SRCCOPY); } - ReleaseDC (hwnd, dc); - return SoftwareImageType().convert (bitmap); } @@ -1025,79 +1039,75 @@ namespace IconConverters && bm.bmWidth > 0 && bm.bmHeight > 0)) return {}; - if (auto* tempDC = ::GetDC (nullptr)) + ScopedDeviceContext deviceContext { nullptr }; + + if (auto* dc = ::CreateCompatibleDC (deviceContext.dc)) { - if (auto* dc = ::CreateCompatibleDC (tempDC)) + BITMAPV5HEADER header = {}; + header.bV5Size = sizeof (BITMAPV5HEADER); + header.bV5Width = bm.bmWidth; + header.bV5Height = -bm.bmHeight; + header.bV5Planes = 1; + header.bV5Compression = BI_RGB; + header.bV5BitCount = 32; + header.bV5RedMask = 0x00FF0000; + header.bV5GreenMask = 0x0000FF00; + header.bV5BlueMask = 0x000000FF; + header.bV5AlphaMask = 0xFF000000; + header.bV5CSType = LCS_WINDOWS_COLOR_SPACE; + header.bV5Intent = LCS_GM_IMAGES; + + uint32* bitmapImageData = nullptr; + + if (auto* dib = ::CreateDIBSection (deviceContext.dc, (BITMAPINFO*) &header, DIB_RGB_COLORS, + (void**) &bitmapImageData, nullptr, 0)) { - BITMAPV5HEADER header = {}; - header.bV5Size = sizeof (BITMAPV5HEADER); - header.bV5Width = bm.bmWidth; - header.bV5Height = -bm.bmHeight; - header.bV5Planes = 1; - header.bV5Compression = BI_RGB; - header.bV5BitCount = 32; - header.bV5RedMask = 0x00FF0000; - header.bV5GreenMask = 0x0000FF00; - header.bV5BlueMask = 0x000000FF; - header.bV5AlphaMask = 0xFF000000; - header.bV5CSType = LCS_WINDOWS_COLOR_SPACE; - header.bV5Intent = LCS_GM_IMAGES; + auto oldObject = ::SelectObject (dc, dib); - uint32* bitmapImageData = nullptr; + auto numPixels = bm.bmWidth * bm.bmHeight; + auto numColourComponents = (size_t) numPixels * 4; - if (auto* dib = ::CreateDIBSection (tempDC, (BITMAPINFO*) &header, DIB_RGB_COLORS, - (void**) &bitmapImageData, nullptr, 0)) + // Windows icon data comes as two layers, an XOR mask which contains the bulk + // of the image data and an AND mask which provides the transparency. Annoyingly + // the XOR mask can also contain an alpha channel, in which case the transparency + // mask should not be applied, but there's no way to find out a priori if the XOR + // mask contains an alpha channel. + + HeapBlock opacityMask (numPixels); + memset (bitmapImageData, 0, numColourComponents); + ::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_MASK); + + for (int i = 0; i < numPixels; ++i) + opacityMask[i] = (bitmapImageData[i] == 0); + + Image result = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true); + Image::BitmapData imageData (result, Image::BitmapData::readWrite); + + memset (bitmapImageData, 0, numColourComponents); + ::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_NORMAL); + memcpy (imageData.data, bitmapImageData, numColourComponents); + + auto imageHasAlphaChannel = [&imageData, numPixels]() { - auto oldObject = ::SelectObject (dc, dib); - - auto numPixels = bm.bmWidth * bm.bmHeight; - auto numColourComponents = (size_t) numPixels * 4; - - // Windows icon data comes as two layers, an XOR mask which contains the bulk - // of the image data and an AND mask which provides the transparency. Annoyingly - // the XOR mask can also contain an alpha channel, in which case the transparency - // mask should not be applied, but there's no way to find out a priori if the XOR - // mask contains an alpha channel. - - HeapBlock opacityMask (numPixels); - memset (bitmapImageData, 0, numColourComponents); - ::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_MASK); - for (int i = 0; i < numPixels; ++i) - opacityMask[i] = (bitmapImageData[i] == 0); + if (imageData.data[i * 4] != 0) + return true; - Image result = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true); - Image::BitmapData imageData (result, Image::BitmapData::readWrite); + return false; + }; - memset (bitmapImageData, 0, numColourComponents); - ::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_NORMAL); - memcpy (imageData.data, bitmapImageData, numColourComponents); - - auto imageHasAlphaChannel = [&imageData, numPixels]() - { - for (int i = 0; i < numPixels; ++i) - if (imageData.data[i * 4] != 0) - return true; - - return false; - }; - - if (! imageHasAlphaChannel()) - for (int i = 0; i < numPixels; ++i) - imageData.data[i * 4] = opacityMask[i] ? 0xff : 0x00; - - ::SelectObject (dc, oldObject); - ::DeleteObject(dib); - ::DeleteDC (dc); - ::ReleaseDC (nullptr, tempDC); - - return result; - } + if (! imageHasAlphaChannel()) + for (int i = 0; i < numPixels; ++i) + imageData.data[i * 4] = opacityMask[i] ? 0xff : 0x00; + ::SelectObject (dc, oldObject); + ::DeleteObject (dib); ::DeleteDC (dc); + + return result; } - ::ReleaseDC (nullptr, tempDC); + ::DeleteDC (dc); } return {};