【问题标题】:Win32: UpdateLayeredWindow failing sometimes (error 317)Win32:UpdateLayeredWindow 有时会失败(错误 317)
【发布时间】:2016-03-04 01:26:13
【问题描述】:

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

提前感谢您的帮助!

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_nWndWidth, m_nWndHeight );
        HBITMAP hBmpOld = ( HBITMAP ) ::SelectObject( hDC, hBmp );

        img.Draw( hDC, 0, 0, m_nWndWidth, m_nWndHeight, 0, 0, m_nWndWidth, 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, 0, &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 线程上运行。它总是在我的机器上运行......

【问题讨论】:

    标签: mfc png


    【解决方案1】:

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

    【讨论】:

    • 是的,我想不通。如果我检测到 UpdateLayeredWindow 调用失败,我最终会显示位图而不是 PNG。不过,感谢您的回复,克里斯。
    【解决方案2】:

    我已经让 UpdateLayeredWindow() 在 Windows 7 x86_64 机器上完美运行,只是当我禁用桌面合成时它开始失败。原来是这样的

    UpdateLayeredWindow (window_handle, NULL,
                         &position, &size,
                         buffer_hdc, &buffer_offset,
                         0, &blend_options, ULW_ALPHA);
    

    工作,而

    UpdateLayeredWindow (window_handle, NULL,
                         &position, NULL,
                         buffer_hdc, &buffer_offset,
                         0, &blend_options, ULW_ALPHA);
    

    不起作用并失败并出现错误 317。

    我一直试图跳过一些参数,因为我不需要更改窗口大小或内容,只需移动它。禁用桌面合成后,这是不可能的。

    不确定这与您的原始问题有何关系,因为您还提供屏幕 DC,而我没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 2018-03-09
      • 2017-04-21
      • 1970-01-01
      • 1970-01-01
      • 2012-12-28
      相关资源
      最近更新 更多