Получение HBITMAP из многоуровневого окна — неверные данные

Я создал многослойное окно (с WS_EX_LAYERED), размером около 400X300 пикселей.
При рисовании окна (используя UpdateLayeredWindow) все отлично работает.

Проблема в том, что я не могу получить HBITMAP окна после его рисования.
При попытке получить HBITMAP через HDC окна, я получаю пустое (черное) растровое изображение, размером с весь мой рабочий стол (1920×1080 px, 400X300 px).

Кто-нибудь знает, возможно ли даже получить HDC \ HBITMAP многослойного окна?

Образцы кода

Вот код того, как я рисую многоуровневое окно (опять же, прекрасно работает):

void MyLayeredWindow::DrawLayered() const
{
RECT rcWindow;
GetWindowRect(rcWindow);

int nWidth = abs(rcWindow.right - rcWindow.left);
int nHeight = abs(rcWindow.bottom - rcWindow.top);

// Create 32Bit bitmap to apply transparency
// (have to set negative height because if not the (0,0) point would be the bottom left instead of top left)
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;

// Copy view buffer to a temp DC and bitmap
HDC hDcTemp = ::CreateCompatibleDC(NULL);
assert(hDcTemp);
HBITMAP hBitmapTemp = ::CreateDIBSection(hDcTemp, &BitmapInfo, DIB_RGB_COLORS, &ppvBits, NULL, 0);
assert(hBitmapTemp && hBitmapTemp!=(HBITMAP)ERROR_INVALID_PARAMETER)
::SelectObject(hDcTemp, hBitmapTemp);

// Darwing the window's conent here
// ....
// ....

// Call UpdateLayeredWindow
BLENDFUNCTION blend = {0};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 190;
blend.AlphaFormat = AC_SRC_ALPHA;

SIZE sizeWnd = {0};
sizeWnd.cx = nWidth;
sizeWnd.cy = nHeight;
POINT ptPos = {0};
ptPos.x = rcWindow.left;
ptPos.y = rcWindow.top;
POINT ptSrc = {0,0};

::UpdateLayeredWindow(m_hWnd, NULL, &ptPos, &sizeWnd, hDcTemp, &ptSrc, 0, &blend, ULW_ALPHA);

if(hDcTemp)
::DeleteDC(hDcTemp);

if(hBitmapTemp)
::DeleteObject(hBitmapTemp);
}

Вот код того, как я фиксирую растровое изображение окна и сохраняю его в файл:
(ВНИМАНИЕ: Работает из «нормальных» окон, таких как Калькулятор)

bool MyLayeredWindow::SaveBitmapFile(__in const HWND& hWnd, __in const wstring& sFileName)
{
HDC hDC = ::GetDC(hWnd);

// get bitmap of DC
HBITMAP hBmp = (HBITMAP)::GetCurrentObject( hDC, OBJ_BITMAP );

// get info of bitmap
BITMAPINFO stBmpInfo;
stBmpInfo.bmiHeader.biSize = sizeof( stBmpInfo.bmiHeader );
stBmpInfo.bmiHeader.biBitCount = 0;
GetDIBits( hDC, hBmp, 0, 0, NULL, &stBmpInfo, DIB_RGB_COLORS );

// init info size
ULONG iBmpInfoSize;
switch( stBmpInfo.bmiHeader.biBitCount )
{
case 24:
iBmpInfoSize = sizeof(BITMAPINFOHEADER);
break;
case 16:
case 32:
iBmpInfoSize = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
break;
default:
iBmpInfoSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ( 1 << stBmpInfo.bmiHeader.biBitCount );
break;
}

// copy header
PBITMAPINFO pstBmpInfo = NULL;
if( iBmpInfoSize != sizeof(BITMAPINFOHEADER) )
{
pstBmpInfo = (PBITMAPINFO)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, iBmpInfoSize );
PBYTE pbtBmpInfoDest = (PBYTE)pstBmpInfo;
PBYTE pbtBmpInfoSrc = (PBYTE)&stBmpInfo;
ULONG iSizeTmp = sizeof( BITMAPINFOHEADER );

while( iSizeTmp-- )
*( ( pbtBmpInfoDest )++ ) = *( ( pbtBmpInfoSrc )++ );
}

// create file
HANDLE hFile = CreateFile( sFileName.c_str(), GENERIC_WRITE, 0 , NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL );

// init bmp file header
BITMAPFILEHEADER stBmpFileHder = {0};
stBmpFileHder.bfType = 0x4D42; // 'BM'
stBmpFileHder.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + iBmpInfoSize + pstBmpInfo->bmiHeader.biSizeImage;
stBmpFileHder.bfReserved1 = 0;
stBmpFileHder.bfReserved2 = 0;
stBmpFileHder.bfOffBits = sizeof(BITMAPFILEHEADER) + iBmpInfoSize;

// write header to file
DWORD dRet;
WriteFile( hFile, (LPCVOID)&stBmpFileHder, sizeof(BITMAPFILEHEADER), &dRet, NULL );

// allocate size for rest of bmp (body)
PBYTE pBits = (PBYTE)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, stBmpInfo.bmiHeader.biSizeImage );

// get bmp bits
HBITMAP hBmpOld;
HBITMAP hTmpBmp = CreateCompatibleBitmap( hDC, pstBmpInfo->bmiHeader.biWidth, pstBmpInfo->bmiHeader.biHeight );
hBmpOld = (HBITMAP)SelectObject( hDC, hTmpBmp );
GetDIBits( hDC, hBmp, 0, pstBmpInfo->bmiHeader.biHeight, (LPSTR)pBits, pstBmpInfo, DIB_RGB_COLORS );

// write bmp info
WriteFile( hFile, (LPCVOID)pstBmpInfo, iBmpInfoSize, &dRet, NULL );

// write bmp bits
WriteFile( hFile, (LPCVOID)pBits, pstBmpInfo->bmiHeader.biSizeImage, &dRet, NULL );

// release handles and free memory
SelectObject( hDC, hBmpOld );
DeleteObject( hTmpBmp );
CloseHandle( hFile );
GlobalFree( pstBmpInfo );
GlobalFree( pBits );
ReleaseDC( hWnd, hDC );

return true;
}

Спасибо!

2

Решение

Поскольку лучшего ответа я не получил, я просто вызвал функцию «Рисование», которая рисует мое многоуровневое окно на временный HDC.

Это значит, что я не копирую существующее растровое изображение, а создаю идентичный, используя ту же функцию рисования.

Я все еще хотел бы получить лучший ответ на этот вопрос.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]