从分层窗口获取HBITMAP - 数据不正确

3
我创建了一个大小约为400x300像素的分层窗口(使用WS_EX_LAYERED)。 当使用UpdateLayeredWindow进行绘制时,一切都很好。
问题是,在绘制窗口后,我无法获取该窗口的HBITMAP。 尝试通过窗口的HDC获取HBITMAP时,我得到一个空(黑色)位图,大小为整个桌面的1920x1080像素而不是400x300像素。
有人知道是否可以获取分层窗口的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;
}

谢谢!


这种方法通常是错误的,只能偶然起作用。窗口没有位图,您需要使用BitBlt或PrintWindow。对于分层窗口,请使用CAPTURE_BLT选项。http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402%28v=vs.85%29.aspx - Hans Passant
BitBlt和PrintWindow似乎不适用于我的分层窗口。它返回一个空的(黑色\透明)DC。 - Bagelzone Ha'bonè
1个回答

0

由于我没有得到更好的答案,我只是调用了一个“绘制”函数,将我的分层窗口绘制到一个临时HDC上。

这意味着我不是复制现有的位图,而是使用相同的绘制函数创建一个相同的位图。

我仍然希望能够得到一个更好的答案来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接