mfc – Win32:UpdateLayeredWindow有时会失败(错误317)

我这里有一个奇怪的问题.我正在使用分层窗口显示半透明的启动画面(.png文件).它适用于某些机器但不适用于其他机器.在它不起作用的机器上,GetLastError返回317(这不是很有用).有谁之前经历过这个吗?这是我的相关功能. CreateAsPNG的传入参数是WS_VISIBLE | WS_POPUP(dwStyle),0(dwExStyle),以及父级隐藏工具窗口的句柄,因此不会创建任务栏条目.我已经验证我可以将嵌入的PNG资源加载到C Image中,并且图像的大小是正确的.

在此先感谢您的帮助!

BOOL MySplashWnd::CreateAsPNG( DWORD dwStyle,DWORD dwExStyle,const CString& sTitle,HWND hWndParent )
{
    ATL::CImage img;
    CreateStreamOnResource( m_nBitmapID,img );

    m_nWndWidth = img.GetWidth();
    m_nWndHeight = img.GetHeight();

    int nTop = 0;
    int nLeft = 0;
    GetTopLeft( nTop,nLeft );

    dwExStyle |= WS_EX_LAYERED;

    // Create the Splash Window
    BOOL bRetVal = CWnd::CreateEx( dwExStyle,AfxRegisterWndClass( CS_CLASSDC ),sTitle,dwStyle,nLeft,nTop,m_nWndWidth,m_nWndHeight,hWndParent,NULL );

    //Couldn't create the window for some unknown reason...
    X_ASSERT( bRetVal != FALSE );

    if ( bRetVal )
    {
        HDC hScreenDC = ::GetDC( m_hWnd );
        HDC hDC = ::CreateCompatibleDC( hScreenDC );
        HBITMAP hBmp = ::CreateCompatibleBitmap( hScreenDC,m_nWndHeight );
        HBITMAP hBmpOld = ( HBITMAP ) ::SelectObject( hDC,hBmp );

        img.Draw( hDC,m_nWndHeight );

        BLENDFUNCTION blend = { 0 };
        blend.BlendOp = AC_SRC_OVER;
        blend.BlendFlags = 0;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat = AC_SRC_ALPHA;

        POINT ptPos = { nLeft,nTop };
        SIZE sizeWnd = { m_nWndWidth,m_nWndHeight };
        POINT ptSource = { 0,0 };

        if ( ::UpdateLayeredWindow( m_hWnd,hScreenDC,&ptPos,&sizeWnd,hDC,&ptSource,&blend,ULW_ALPHA ) )
        {
        }
        else
        {
            // The last error value is 317 on some Win7 machines.
            TRACE( _T( "*** Last error: %d\n" ),::GetLastError() );
        }

        ::SelectObject( hDC,hBmpOld );
        ::DeleteObject( hBmp );
        ::DeleteDC( hDC );
        ::ReleaseDC( NULL,hScreenDC );
    }

    return bRetVal;
}

void MySplashWnd::CreateStreamOnResource( UINT nIDRes,ATL::CImage& img )
{
    HINSTANCE hInstance = ::GetMUIResourceInstance();
    if ( hInstance == NULL )
    {
        return;
    }

    HRSRC hResource = ::FindResource( hInstance,MAKEINTRESOURCE( nIDRes ),"PNG" );
    if ( hResource == NULL )
    {
        return;
    }

    DWORD dwResourceSize = ::SizeofResource( hInstance,hResource );
    if ( dwResourceSize == 0 )
    {
        return;
    }

    HGLOBAL hImage = ::LoadResource( hInstance,hResource );
    if ( hImage == NULL )
    {
        return;
    }

    LPVOID pvImageResourceData = ::LockResource( hImage );
    if ( pvImageResourceData == nullptr )
    {
        return;
    }

    HGLOBAL hImageData = ::GlobalAlloc( GMEM_MOVEABLE,dwResourceSize );
    if ( hImageData == NULL )
    {
        return;
    }

    LPVOID pvImageBuffer = ::GlobalLock( hImageData );
    if ( pvImageBuffer != nullptr )
    {
        ::CopyMemory( pvImageBuffer,pvImageResourceData,dwResourceSize );
        ::GlobalUnlock( hImageData );

        IStream* pStream = nullptr;

        if ( SUCCEEDED( ::CreateStreamOnHGlobal( hImageData,TRUE,&pStream ) ) )
        {
            img.Load( pStream );
            pStream->Release();
        }

        ::GlobalUnlock( hImageData );
    }

    ::GlobalFree( hImageData );
} // CTTSplashWnd::CreateStreamOnResource

更新:我发现即使在同一台机器上,有时UpdateLayeredWindow会成功,有时会失败(但如果失败则始终使用代码317).另一条信息是这个启动是在一个单独的UI线程上运行的.它总是适用于我的机器…

解决方法

我遇到了同样的问题,我也找不到任何信息.使用SetWindowAttributes方法可以工作,但我想使用SetLayeredWindow方式.我将要通过整个Windows API进行调试,以了解发生了什么,因为msdn提供了有关此错误消息的插孔信息.唯一的区别是我看到的使用此方法的OpenGL分层窗口演示示例使用CreateDIBSection而不是CreateCompatibleBitmap,它似乎可以在我的PC上运行.

相关文章

文章浏览阅读2.2k次,点赞6次,收藏20次。在我们平时办公工作...
文章浏览阅读1k次。解决 Windows make command not found 和...
文章浏览阅读3.2k次,点赞2次,收藏6次。2、鼠标依次点击“计...
文章浏览阅读1.3w次。蓝光版属于高清版的一种。BD英文全名是...
文章浏览阅读974次,点赞7次,收藏8次。提供了更强大的功能,...
文章浏览阅读1.4w次,点赞5次,收藏22次。如果使用iterator的...