Restablecer HBITMAP existente como fondo de escritorio (WIN32)
Pregunta
Deseo crear una ventana transparente sobre el escritorio.
Para ese propósito, he creado un HDC con un fondo del escritorio (creado HBITMAP del escritorio y lo apliqué a mi HDC) e invocado UpdateLayerDwindow.
Hasta aquí todo bien.
Para problemas de rendimiento, necesito mantener un objeto GDI+ persistente, lo que significa que mi HDC y HBITMAP deben mantener las mismas manijas entre las pinturas (suponiendo que el escritorio DC no cambió), igual que en esta pregunta.
En la primera iteración de pintura todo va bien. En la segunda iteración de pintura, dado que el HDC y el HBITMAP no han cambiado, repinto en el HDC existente, lo que significa que obtengo imágenes dobles (el fondo no se borra).
Aquí hay un ejemplo de código de lo que estoy haciendo:
bool SomeUI::Draw()
{
BLENDFUNCTION blend = {0};
POINT ptPos = {0};
SIZE sizeWnd = {0};
POINT ptSrc = {0};
BOOL bUpdate = FALSE;
// Get the client rect
RECT rctWindow;
bool bGot = GetWindowRect(rctWindow);
if (!bGot)
return false;
// Get the desktop's device context
HDC hDCDesktop = GetDC(NULL);
if (!hDCDesktop)
return false;
int nWidth = abs(rctWindow.right - rctWindow.left);
int nHeight = abs(rctWindow.bottom - rctWindow.top);
// Create 32Bit bitmap to apply PNG transparency
VOID *ppvBits = NULL;
BITMAPINFO BitmapInfo = {0};
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth = nWidth;
BitmapInfo.bmiHeader.biHeight = nHeight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
HBITMAP hBmp = CreateDIBSection(hDCDesktop, &BitmapInfo, DIB_RGB_COLORS, &ppvBits, NULL, 0);
if (!hBmp || hBmp==(HBITMAP)ERROR_INVALID_PARAMETER)
goto releaseHandles;
// Create a compatible DC and select the newly created bitmap
if (!m_hDC)
{
m_hDC = CreateCompatibleDC(hDCDesktop);
if (!m_hDC)
goto releaseHandles;
SelectObject(m_hDC, hBmp);
}
else
{
///////////////////////////////////////////////////////////////////////
//
// The problem lies here, this is where I need to reset the HBITMAP
// according to the desktop here (to have a transparent DC to work on)
//
///////////////////////////////////////////////////////////////////////
}
// The drawing logic
bool bInnerDraw = Draw(m_hDC);
if (!bInnerDraw)
goto releaseHandles;
// Call UpdateLayeredWindow
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
sizeWnd.cx = nWidth;
sizeWnd.cy = nHeight;
ptPos.x = rctWindow.left;
ptPos.y = rctWindow.top;
bUpdate = UpdateLayeredWindow(m_hWnd, hDCDesktop, &ptPos, &sizeWnd, m_hDC, &ptSrc, 0, &blend, ULW_ALPHA);
if (!bUpdate)
goto releaseHandles;
releaseHandles:
// releasing handles
}
¿Algunas ideas?
Solución
Encontré la respuesta:
Para restablecer el HBITMAP persistente (Recordatorio: debe mantener el mismo mango), estableceremos los antecedentes de escritorio de esa área en un HBITMAP temporal y lo copiaremos en el HBITMAP persistente.
Para lograr eso (copiar de un HBITMAP al otro), crearemos un HDC temporal y seleccionaremos el HBITMAP temporal y copiaremos el HDC temporal al HDC persistente, USIST Bitblt
Aquí está el código:
hBmpTemp = CreateDIBSection(hDCDesktop, &BitmapInfo, DIB_RGB_COLORS, &ppvBits, NULL, 0);
if (!hBmpTemp || hBmpTemp==(HBITMAP)ERROR_INVALID_PARAMETER)
goto releaseHandles;
HDC hTempDC = CreateCompatibleDC(NULL);
if (!hTempDC)
goto releaseHandles;
SelectObject(hTempDC, hBmpTemp);
::BitBlt(m_hPersistentDC, 0, 0, nWidth, nHeight, hTempDC, rctWindow.left, rctWindow.top, SRCCOPY);
::DeleteDC(hTempDC);