Reputation: 185
I have a bizarre issue here. I'm displaying a semi-transparent splash screen (a .png file) using layered windows. It works on some machines but not others. On the machines where it doesn't work, the GetLastError returns 317 (which isn't very helpful). Has anyone experienced this before? Here are my relevant functions. The incoming parameters for CreateAsPNG are WS_VISIBLE|WS_POPUP (dwStyle), 0 (dwExStyle), and the handle to a hidden tool window for the parent so no taskbar entry is created. I've verified that I can load an embedded PNG resource into CImage and that the size of the image is correct.
Thanks in advance for any help!
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
UPDATE: I've found that even on the same machine, sometimes UpdateLayeredWindow succeeds and other time it fails (but always with code 317 if it does fail). Another piece of info is that this splash is being run on a separate UI thread. It always works on my machine though...
Upvotes: 4
Views: 1044
Reputation: 1883
I've had UpdateLayeredWindow() work perfectly on a Windows 7 x86_64 machine only for it to start failing when i've disabled desktop composition. It turned out that
UpdateLayeredWindow (window_handle, NULL,
&position, &size,
buffer_hdc, &buffer_offset,
0, &blend_options, ULW_ALPHA);
works, while
UpdateLayeredWindow (window_handle, NULL,
&position, NULL,
buffer_hdc, &buffer_offset,
0, &blend_options, ULW_ALPHA);
does not work and fails with error 317.
I've been trying to skip some of the arguments because i didn't need to change window size or contents, just to move it. With desktop composition disabled, this turned out to be impossible.
Not sure how this relates to your original problem, as you're also supplying the screen DC, while i don't.
Upvotes: 1
Reputation: 21
I'm having this same problem and I can't find any info either on it. Using SetWindowAttributes method instead works, but I want to use the SetLayeredWindow way. I'm coming to the point where I'm going to debug through the whole windows API to find out what is happening since msdn gives jack info about this error message. The only difference is that the OpenGL layered window demo example I saw which uses this method, uses CreateDIBSection instead of CreateCompatibleBitmap which seems to work on my PC.
Upvotes: 2