SplashScreen.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / Windows / SplashScreen.cs / 1305600 / SplashScreen.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
// 
// History:
//  02/18/2008: [....]: Created 
//
//---------------------------------------------------------------------------

using System.ComponentModel; 
using System.IO;
using System.Reflection; 
using System.Resources; 
using System.Runtime.InteropServices;
using System.Security; 
using System.Security.Permissions;
using System.Windows.Threading;
using MS.Internal;
using MS.Internal.Interop; 
using MS.Internal.KnownBoxes;
using MS.Internal.WindowsBase; 
using MS.Utility; 
using MS.Win32;
 
namespace System.Windows
{
    /// 
    /// This class has been reviewed under the assumption that it is not used in partial trust. 
    /// If this changes all methods will need to be re-reviewed.
    ///  
    [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)] 
    public class SplashScreen
    { 
        private IntPtr _hwnd = IntPtr.Zero;
        private string _resourceName;
        private IntPtr _hInstance;
        private NativeMethods.BitmapHandle _hBitmap; 
        private ushort _wndClass;
        private DispatcherTimer _dt; 
        private TimeSpan _fadeoutDuration; 
        private DateTime _fadeoutEnd;
        NativeMethods.BLENDFUNCTION _blendFunc; 
        private ResourceManager _resourceManager;
        private Dispatcher _dispatcher;
        // keep this delegate alive as long as the window class is registered
        private static NativeMethods.WndProc _defWndProc; 

        private const string CLASSNAME = "SplashScreen"; 
 
        public SplashScreen(string resourceName) : this(Assembly.GetEntryAssembly(), resourceName)
        { 
        }

        /// 
        ///         Critical: Calls Marshal.GetHINSTANCE 
        ///         PublicOK: Does not expose HINSTANCE.
        ///                   Not available in partial trust. 
        ///  
        [SecurityCritical]
        public SplashScreen(Assembly resourceAssembly, string resourceName) 
        {
            if (resourceAssembly == null)
            {
                throw new ArgumentNullException("resourceAssembly"); 
            }
            if (String.IsNullOrEmpty(resourceName)) 
            { 
                throw new ArgumentNullException("resourceName");
            } 
            _resourceName = resourceName.ToLowerInvariant();
            _hInstance = Marshal.GetHINSTANCE(resourceAssembly.ManifestModule);
            AssemblyName name = new AssemblyName(resourceAssembly.FullName);
            _resourceManager = new ResourceManager(name.Name + ".g", resourceAssembly); 
        }
 
        public void Show(bool autoClose) 
        {
            Show(autoClose, false); 
        }

        /// 
        ///         Critical: Calls CreateLayeredWindowFromImgBuffer 
        ///         PublicOk: This class is not available in partial trust.
        ///                   The created window handle is not exposed. 
        /// 
        /// 
        [SecurityCritical] 
        public void Show(bool autoClose, bool topMost)
        {
            // If we've already been shown it isn't an error to call show
            // again (maybe you forgot) since you will still be shown state. 
            if (_hwnd == IntPtr.Zero)
            { 
                UnmanagedMemoryStream umemStream; 
                using (umemStream = GetResourceStream())
                { 
                    if (umemStream != null)
                    {
                        umemStream.Seek(0, SeekOrigin.Begin); // ensure stream position
                        IntPtr pImageSrcBuffer; 
                        unsafe
                        { 
                            pImageSrcBuffer = new IntPtr(umemStream.PositionPointer); 
                        }
 
                        if (CreateLayeredWindowFromImgBuffer(pImageSrcBuffer, umemStream.Length, topMost) && autoClose == true)
                        {
                            Dispatcher.CurrentDispatcher.BeginInvoke(
                                DispatcherPriority.Loaded, 
                                (DispatcherOperationCallback)delegate(object splashObj)
                                { 
                                    SplashScreen splashScreen = (SplashScreen)splashObj; 
                                    splashScreen.Close(TimeSpan.FromSeconds(0.3));
                                    return null; 
                                },
                                this);
                        }
                        // The HWND that we just created is owned by this thread.  When we close we should ensure that it 
                        // does not get accessed from a different thread.  We don't want to reference the .CurrentDispatcher
                        // property before the window is created due to cold start performance concerns. 
                        _dispatcher = Dispatcher.CurrentDispatcher; 
                    }
                    else 
                    {
                        throw new IOException(SR.Get(SRID.UnableToLocateResource, _resourceName));
                    }
                } 
            }
        } 
 
        // This is 200-300 ms slower than Assembly.GetManifestResourceStream() but works with localization.
        private UnmanagedMemoryStream GetResourceStream() 
        {
            // Try to get the stream with the string the developer supplied, in the app.g.cs case
            // this will always work.
            UnmanagedMemoryStream stream = _resourceManager.GetStream(_resourceName, System.Globalization.CultureInfo.CurrentUICulture); 
            if (stream != null)
            { 
                return stream; 
            }
 
            // IF that fails then the resource name had special characters in it which would not
            // be encoded literally into the resource stream.  Unfortunately we need to rely on the
            // slow URI class to get the correct name.  We try to avoid doing this in the common case
            // since URI has quite a bit of code associated with it. 
            string resourceName = ResourceIDHelper.GetResourceIDFromRelativePath(_resourceName);
            return _resourceManager.GetStream(resourceName, System.Globalization.CultureInfo.CurrentUICulture); 
        } 

        ///  
        ///         Critical:   Calls UnsafeNativeMethods to create and update a layered window.
        ///                     Manipulates native objects passed in.
        /// 
        [SecurityCritical] 
        private IntPtr CreateWindow(NativeMethods.BitmapHandle hBitmap, int width, int height, bool topMost)
        { 
            if (_defWndProc == null) 
            {
                _defWndProc = new MS.Win32.NativeMethods.WndProc(UnsafeNativeMethods.DefWindowProc); 
            }

            MS.Win32.NativeMethods.WNDCLASSEX_D wndClass = new MS.Win32.NativeMethods.WNDCLASSEX_D();
            wndClass.cbSize = Marshal.SizeOf(typeof(MS.Win32.NativeMethods.WNDCLASSEX_D)); 
            wndClass.style = 3; /* CS_HREDRAW | CS_VREDRAW */
            wndClass.lpfnWndProc = null; 
            wndClass.hInstance = _hInstance; 
            wndClass.hCursor = IntPtr.Zero;
            wndClass.lpszClassName = CLASSNAME; 
            wndClass.lpszMenuName = string.Empty;
            wndClass.lpfnWndProc = _defWndProc;

            // We chose to ignore re-registration errors in RegisterClassEx on the off chance that the user 
            // wants to open multiple splash screens.
            _wndClass = MS.Win32.UnsafeNativeMethods.IntRegisterClassEx(wndClass); 
            if (_wndClass == 0) 
            {
                if (Marshal.GetLastWin32Error() != 0x582) /* class already registered */ 
                    throw new Win32Exception();
            }

            int screenWidth = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CXSCREEN); 
            int screenHeight = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CYSCREEN);
            int x = (screenWidth - width) / 2; 
            int y = (screenHeight - height) / 2; 

            HandleRef nullHandle = new HandleRef(null, IntPtr.Zero); 
            int windowCreateFlags =
                (int) NativeMethods.WS_EX_WINDOWEDGE |
                      NativeMethods.WS_EX_TOOLWINDOW |
                      NativeMethods.WS_EX_LAYERED | 
                      (topMost ? NativeMethods.WS_EX_TOPMOST : 0);
 
            // CreateWindowEx will either succeed or throw 
            IntPtr hWnd =  MS.Win32.UnsafeNativeMethods.CreateWindowEx(
                windowCreateFlags, 
                CLASSNAME, SR.Get(SRID.SplashScreenIsLoading),
                MS.Win32.NativeMethods.WS_POPUP | MS.Win32.NativeMethods.WS_VISIBLE,
                x, y, width, height,
                nullHandle, nullHandle, new HandleRef(null, _hInstance), IntPtr.Zero); 

            // Display the image on the window 
            IntPtr hScreenDC = UnsafeNativeMethods.GetDC(new HandleRef()); 
            IntPtr memDC = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hScreenDC));
            IntPtr hOldBitmap = UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hBitmap.MakeHandleRef(null).Handle); 

            NativeMethods.POINT newSize = new NativeMethods.POINT(width, height);
            NativeMethods.POINT newLocation = new NativeMethods.POINT(x, y);
            NativeMethods.POINT sourceLocation = new NativeMethods.POINT(0, 0); 
            _blendFunc = new NativeMethods.BLENDFUNCTION();
            _blendFunc.BlendOp = NativeMethods.AC_SRC_OVER; 
            _blendFunc.BlendFlags = 0; 
            _blendFunc.SourceConstantAlpha = 255;
            _blendFunc.AlphaFormat = 1; /*AC_SRC_ALPHA*/ 

            bool result = UnsafeNativeMethods.UpdateLayeredWindow(hWnd, hScreenDC, newLocation, newSize,
                memDC, sourceLocation, 0, ref _blendFunc, NativeMethods.ULW_ALPHA);
 
            UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hOldBitmap);
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, memDC)); 
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, hScreenDC)); 

            if (result == false) 
            {
                UnsafeNativeMethods.HRESULT.Check(Marshal.GetHRForLastWin32Error());
            }
 
            return hWnd;
        } 
 
        /// 
        ///     Critical: Call SetActiveWindow to make sure the fade out animation is visible (if a fade out is specified) 
        ///     PublicOK: Only the splash screen window can be activated.
        ///               This class is not available in partial trust.
        /// 
        [SecurityCritical] 
        public void Close(TimeSpan fadeoutDuration)
        { 
            object result = null; 
            if (_dispatcher != null)
            { 
                if (_dispatcher.CheckAccess())
                {
                    result = CloseInternal(fadeoutDuration);
                } 
                else
                { 
                    result = _dispatcher.Invoke(DispatcherPriority.Normal, (DispatcherOperationCallback)CloseInternal, fadeoutDuration); 
                }
            } 

            if (result != BooleanBoxes.TrueBox)
            {
                // If all else fails try to destroy the resources on this thread 
                // this will probably end up throwing but it will be the same
                // exception as the previous version. 
                DestroyResources(); 
            }
        } 


        private object CloseInternal(Object fadeOutArg)
        { 
            TimeSpan fadeoutDuration = (TimeSpan) fadeOutArg;
            if (fadeoutDuration <= TimeSpan.Zero) 
            { 
                DestroyResources();
                return BooleanBoxes.TrueBox; 
            }

            // In the case where the developer has specified AutoClose=True and then calls
            // Close(non_zero_timespan) before the auto close operation is dispatched we begin 
            // the fadeout immidiately and ignore the later call to close.
            if (_dt != null || _hwnd == null) 
            { 
                return BooleanBoxes.TrueBox;
            } 

            // by default close gets called as soon as the first application window is created
            // since it will have become the active window we need to steal back the active window
            // status so that the fade out animation is visible. 
            IntPtr prevHwnd = UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, _hwnd));
            if (prevHwnd == IntPtr.Zero) 
            { 
                // SetActiveWindow fails (returns NULL) if the application is not in the foreground.
                // If this is the case, don't bother animating the fade out. 
                DestroyResources();
                return BooleanBoxes.TrueBox;
            }
 
            _dt = new DispatcherTimer();
            _dt.Interval = TimeSpan.FromMilliseconds(30); // shoot for ~30 fps 
            _fadeoutDuration = fadeoutDuration; 
            _fadeoutEnd = DateTime.UtcNow + _fadeoutDuration;
            _dt.Tick += new EventHandler(Fadeout_Tick); 
            _dt.Start();

            return BooleanBoxes.TrueBox;
        } 

        ///  
        /// Critical: Calls UpdateLayeredWindow to set a new opacity. 
        /// TreatAsSafe: The layered window is not exposed to the user for tampering and setting the opacity of
        ///              the splash screen is not dangerous. 
        ///              This class is not available in partial trust.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void Fadeout_Tick(object unused, EventArgs args) 
        {
            DateTime dtNow = DateTime.UtcNow; 
            if (dtNow >= _fadeoutEnd) 
            {
                DestroyResources(); 
            }
            else
            {
                double progress = (_fadeoutEnd - dtNow).TotalMilliseconds / _fadeoutDuration.TotalMilliseconds; 
                _blendFunc.SourceConstantAlpha = (byte)(255 * progress);
                UnsafeNativeMethods.UpdateLayeredWindow(_hwnd, IntPtr.Zero, null, null, IntPtr.Zero, null, 0, ref _blendFunc, NativeMethods.ULW_ALPHA); 
            } 
        }
 
        /// 
        ///     Critical: Calls into UnsafeNativeMethods to free resources
        ///     TreatAsSafe: Only frees resources allocated by this class and stored privately.
        ///                  Checks that resource pointers are valid before attempting to free them. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void DestroyResources() 
        {
            if (_dt != null) 
            {
                _dt.Stop();
                _dt = null;
            } 
            if (_hwnd != IntPtr.Zero)
            { 
                HandleRef hwnd = new HandleRef(null, _hwnd); 
                if (UnsafeNativeMethods.IsWindow(hwnd))
                { 
                    UnsafeNativeMethods.IntDestroyWindow(hwnd);
                }
                _hwnd = IntPtr.Zero;
            } 
            if (_hBitmap != null && !_hBitmap.IsClosed)
            { 
                UnsafeNativeMethods.DeleteObject(_hBitmap.MakeHandleRef(null).Handle); 
                _hBitmap.Close();
                _hBitmap = null; 
            }
            if (_wndClass != 0)
            {
                // Attempt to unregister the window class.  If the application has a second 
                // splash screen which is still open this call will fail.  That's OK.
                if (UnsafeNativeMethods.IntUnregisterClass(new IntPtr(_wndClass), _hInstance) != 0) 
                { 
                    _defWndProc = null; // Can safely release the wndproc delegate when there are no more splash screen instances
                } 
                _wndClass = 0;
            }
            if (_resourceManager != null)
            { 
                _resourceManager.ReleaseAllResources();
            } 
        } 

        ///  
        ///     Critical:   Calls out to WIC to decode the image buffer.
        ///                 Calls out to several other UnsafeNativeMethods to get DC and create a DDB.
        /// 
        [SecurityCritical] 
        private bool CreateLayeredWindowFromImgBuffer(IntPtr pImgBuffer, long cImgBufferLen, bool topMost)
        { 
            bool bSuccess = false; 
            IntPtr pImagingFactory = IntPtr.Zero;
            IntPtr pDecoder = IntPtr.Zero; 
            IntPtr pIStream = IntPtr.Zero;
            IntPtr pDecodedFrame = IntPtr.Zero;
            IntPtr pBitmapSourceFormatConverter = IntPtr.Zero;
            IntPtr pBitmapFlipRotator = IntPtr.Zero; 

            try 
            { 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateImagingFactory(UnsafeNativeMethods.WIC.WINCODEC_SDK_VERSION, out pImagingFactory)); 

                // Use the WIC stream class to wrap the unmanaged pointer
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateStream(pImagingFactory, out pIStream)); 

                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeStreamFromMemory(pIStream, pImgBuffer, (uint)cImgBufferLen)); 

                // Create an object that will decode the encoded image 
                Guid vendor = Guid.Empty;
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateDecoderFromStream(pImagingFactory, pIStream,
                                                                    ref vendor, 0, out pDecoder)); 

                // Get the frame from the decoder. Most image formats have only a single frame, in the case 
                // of animated gifs we are ok with only displaying the first frame of the animation. 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.GetFrame(pDecoder, 0, out pDecodedFrame)); 

                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateFormatConverter(pImagingFactory, out pBitmapSourceFormatConverter));
 
                // Convert the image from whatever format it is in to 32bpp premultiplied alpha BGRA
                Guid pixelFormat = UnsafeNativeMethods.WIC.WICPixelFormat32bppPBGRA; 
                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeFormatConverter(pBitmapSourceFormatConverter, pDecodedFrame,
                                                                      ref pixelFormat, 0 /*DitherTypeNone*/, IntPtr.Zero, 
                                                                      0, UnsafeNativeMethods.WIC.WICPaletteType.WICPaletteTypeCustom));
                // Reorient the image
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateBitmapFlipRotator(pImagingFactory, out pBitmapFlipRotator)); 

                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeBitmapFlipRotator(pBitmapFlipRotator, pBitmapSourceFormatConverter, 
                                                                        UnsafeNativeMethods.WIC.WICBitmapTransformOptions.WICBitmapTransformFlipVertical));
                Int32 width, height; 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.GetBitmapSize(pBitmapFlipRotator, out width, out height));

                Int32 stride = width * 4; 

                // initialize the bitmap header 
                MS.Win32.NativeMethods.BITMAPINFO bmInfo = new MS.Win32.NativeMethods.BITMAPINFO(width, height, 32 /*bpp*/); 
                bmInfo.bmiHeader_biCompression = MS.Win32.NativeMethods.BI_RGB;
                bmInfo.bmiHeader_biSizeImage = (int)(stride * height); 

                // Create a 32bpp DIB.  This DIB must have an alpha channel for UpdateLayeredWindow to succeed.
                IntPtr pBitmapBits = IntPtr.Zero;
                _hBitmap = UnsafeNativeMethods.CreateDIBSection(new HandleRef(), ref bmInfo, 0 /* DIB_RGB_COLORS*/, ref pBitmapBits, IntPtr.Zero, 0); 

                // Copy the decoded image to the new buffer which backs the HBITMAP 
                Int32Rect rect = new Int32Rect(0, 0, width, height); 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CopyPixels(pBitmapFlipRotator, ref rect, stride, stride * height, pBitmapBits)); 

                _hwnd = CreateWindow(_hBitmap, width, height, topMost);

                bSuccess = true; 
            }
            finally 
            { 
                if (pImagingFactory != IntPtr.Zero)
                { 
                    Marshal.Release(pImagingFactory);
                }
                if (pDecoder != IntPtr.Zero)
                { 
                    Marshal.Release(pDecoder);
                } 
                if (pIStream != IntPtr.Zero) 
                {
                    Marshal.Release(pIStream); 
                }
                if (pDecodedFrame != IntPtr.Zero)
                {
                    Marshal.Release(pDecodedFrame); 
                }
                if (pBitmapSourceFormatConverter != IntPtr.Zero) 
                { 
                    Marshal.Release(pBitmapSourceFormatConverter);
                } 
                if (pBitmapFlipRotator != IntPtr.Zero)
                {
                    Marshal.Release(pBitmapFlipRotator);
                } 

                if (bSuccess == false) 
                { 
                    DestroyResources(); // cleans up _hwnd and _hBitmap
                } 
            }

            return bSuccess;
        } 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
// 
// History:
//  02/18/2008: [....]: Created 
//
//---------------------------------------------------------------------------

using System.ComponentModel; 
using System.IO;
using System.Reflection; 
using System.Resources; 
using System.Runtime.InteropServices;
using System.Security; 
using System.Security.Permissions;
using System.Windows.Threading;
using MS.Internal;
using MS.Internal.Interop; 
using MS.Internal.KnownBoxes;
using MS.Internal.WindowsBase; 
using MS.Utility; 
using MS.Win32;
 
namespace System.Windows
{
    /// 
    /// This class has been reviewed under the assumption that it is not used in partial trust. 
    /// If this changes all methods will need to be re-reviewed.
    ///  
    [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)] 
    public class SplashScreen
    { 
        private IntPtr _hwnd = IntPtr.Zero;
        private string _resourceName;
        private IntPtr _hInstance;
        private NativeMethods.BitmapHandle _hBitmap; 
        private ushort _wndClass;
        private DispatcherTimer _dt; 
        private TimeSpan _fadeoutDuration; 
        private DateTime _fadeoutEnd;
        NativeMethods.BLENDFUNCTION _blendFunc; 
        private ResourceManager _resourceManager;
        private Dispatcher _dispatcher;
        // keep this delegate alive as long as the window class is registered
        private static NativeMethods.WndProc _defWndProc; 

        private const string CLASSNAME = "SplashScreen"; 
 
        public SplashScreen(string resourceName) : this(Assembly.GetEntryAssembly(), resourceName)
        { 
        }

        /// 
        ///         Critical: Calls Marshal.GetHINSTANCE 
        ///         PublicOK: Does not expose HINSTANCE.
        ///                   Not available in partial trust. 
        ///  
        [SecurityCritical]
        public SplashScreen(Assembly resourceAssembly, string resourceName) 
        {
            if (resourceAssembly == null)
            {
                throw new ArgumentNullException("resourceAssembly"); 
            }
            if (String.IsNullOrEmpty(resourceName)) 
            { 
                throw new ArgumentNullException("resourceName");
            } 
            _resourceName = resourceName.ToLowerInvariant();
            _hInstance = Marshal.GetHINSTANCE(resourceAssembly.ManifestModule);
            AssemblyName name = new AssemblyName(resourceAssembly.FullName);
            _resourceManager = new ResourceManager(name.Name + ".g", resourceAssembly); 
        }
 
        public void Show(bool autoClose) 
        {
            Show(autoClose, false); 
        }

        /// 
        ///         Critical: Calls CreateLayeredWindowFromImgBuffer 
        ///         PublicOk: This class is not available in partial trust.
        ///                   The created window handle is not exposed. 
        /// 
        /// 
        [SecurityCritical] 
        public void Show(bool autoClose, bool topMost)
        {
            // If we've already been shown it isn't an error to call show
            // again (maybe you forgot) since you will still be shown state. 
            if (_hwnd == IntPtr.Zero)
            { 
                UnmanagedMemoryStream umemStream; 
                using (umemStream = GetResourceStream())
                { 
                    if (umemStream != null)
                    {
                        umemStream.Seek(0, SeekOrigin.Begin); // ensure stream position
                        IntPtr pImageSrcBuffer; 
                        unsafe
                        { 
                            pImageSrcBuffer = new IntPtr(umemStream.PositionPointer); 
                        }
 
                        if (CreateLayeredWindowFromImgBuffer(pImageSrcBuffer, umemStream.Length, topMost) && autoClose == true)
                        {
                            Dispatcher.CurrentDispatcher.BeginInvoke(
                                DispatcherPriority.Loaded, 
                                (DispatcherOperationCallback)delegate(object splashObj)
                                { 
                                    SplashScreen splashScreen = (SplashScreen)splashObj; 
                                    splashScreen.Close(TimeSpan.FromSeconds(0.3));
                                    return null; 
                                },
                                this);
                        }
                        // The HWND that we just created is owned by this thread.  When we close we should ensure that it 
                        // does not get accessed from a different thread.  We don't want to reference the .CurrentDispatcher
                        // property before the window is created due to cold start performance concerns. 
                        _dispatcher = Dispatcher.CurrentDispatcher; 
                    }
                    else 
                    {
                        throw new IOException(SR.Get(SRID.UnableToLocateResource, _resourceName));
                    }
                } 
            }
        } 
 
        // This is 200-300 ms slower than Assembly.GetManifestResourceStream() but works with localization.
        private UnmanagedMemoryStream GetResourceStream() 
        {
            // Try to get the stream with the string the developer supplied, in the app.g.cs case
            // this will always work.
            UnmanagedMemoryStream stream = _resourceManager.GetStream(_resourceName, System.Globalization.CultureInfo.CurrentUICulture); 
            if (stream != null)
            { 
                return stream; 
            }
 
            // IF that fails then the resource name had special characters in it which would not
            // be encoded literally into the resource stream.  Unfortunately we need to rely on the
            // slow URI class to get the correct name.  We try to avoid doing this in the common case
            // since URI has quite a bit of code associated with it. 
            string resourceName = ResourceIDHelper.GetResourceIDFromRelativePath(_resourceName);
            return _resourceManager.GetStream(resourceName, System.Globalization.CultureInfo.CurrentUICulture); 
        } 

        ///  
        ///         Critical:   Calls UnsafeNativeMethods to create and update a layered window.
        ///                     Manipulates native objects passed in.
        /// 
        [SecurityCritical] 
        private IntPtr CreateWindow(NativeMethods.BitmapHandle hBitmap, int width, int height, bool topMost)
        { 
            if (_defWndProc == null) 
            {
                _defWndProc = new MS.Win32.NativeMethods.WndProc(UnsafeNativeMethods.DefWindowProc); 
            }

            MS.Win32.NativeMethods.WNDCLASSEX_D wndClass = new MS.Win32.NativeMethods.WNDCLASSEX_D();
            wndClass.cbSize = Marshal.SizeOf(typeof(MS.Win32.NativeMethods.WNDCLASSEX_D)); 
            wndClass.style = 3; /* CS_HREDRAW | CS_VREDRAW */
            wndClass.lpfnWndProc = null; 
            wndClass.hInstance = _hInstance; 
            wndClass.hCursor = IntPtr.Zero;
            wndClass.lpszClassName = CLASSNAME; 
            wndClass.lpszMenuName = string.Empty;
            wndClass.lpfnWndProc = _defWndProc;

            // We chose to ignore re-registration errors in RegisterClassEx on the off chance that the user 
            // wants to open multiple splash screens.
            _wndClass = MS.Win32.UnsafeNativeMethods.IntRegisterClassEx(wndClass); 
            if (_wndClass == 0) 
            {
                if (Marshal.GetLastWin32Error() != 0x582) /* class already registered */ 
                    throw new Win32Exception();
            }

            int screenWidth = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CXSCREEN); 
            int screenHeight = MS.Win32.UnsafeNativeMethods.GetSystemMetrics(SM.CYSCREEN);
            int x = (screenWidth - width) / 2; 
            int y = (screenHeight - height) / 2; 

            HandleRef nullHandle = new HandleRef(null, IntPtr.Zero); 
            int windowCreateFlags =
                (int) NativeMethods.WS_EX_WINDOWEDGE |
                      NativeMethods.WS_EX_TOOLWINDOW |
                      NativeMethods.WS_EX_LAYERED | 
                      (topMost ? NativeMethods.WS_EX_TOPMOST : 0);
 
            // CreateWindowEx will either succeed or throw 
            IntPtr hWnd =  MS.Win32.UnsafeNativeMethods.CreateWindowEx(
                windowCreateFlags, 
                CLASSNAME, SR.Get(SRID.SplashScreenIsLoading),
                MS.Win32.NativeMethods.WS_POPUP | MS.Win32.NativeMethods.WS_VISIBLE,
                x, y, width, height,
                nullHandle, nullHandle, new HandleRef(null, _hInstance), IntPtr.Zero); 

            // Display the image on the window 
            IntPtr hScreenDC = UnsafeNativeMethods.GetDC(new HandleRef()); 
            IntPtr memDC = UnsafeNativeMethods.CreateCompatibleDC(new HandleRef(null, hScreenDC));
            IntPtr hOldBitmap = UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hBitmap.MakeHandleRef(null).Handle); 

            NativeMethods.POINT newSize = new NativeMethods.POINT(width, height);
            NativeMethods.POINT newLocation = new NativeMethods.POINT(x, y);
            NativeMethods.POINT sourceLocation = new NativeMethods.POINT(0, 0); 
            _blendFunc = new NativeMethods.BLENDFUNCTION();
            _blendFunc.BlendOp = NativeMethods.AC_SRC_OVER; 
            _blendFunc.BlendFlags = 0; 
            _blendFunc.SourceConstantAlpha = 255;
            _blendFunc.AlphaFormat = 1; /*AC_SRC_ALPHA*/ 

            bool result = UnsafeNativeMethods.UpdateLayeredWindow(hWnd, hScreenDC, newLocation, newSize,
                memDC, sourceLocation, 0, ref _blendFunc, NativeMethods.ULW_ALPHA);
 
            UnsafeNativeMethods.SelectObject(new HandleRef(null, memDC), hOldBitmap);
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, memDC)); 
            UnsafeNativeMethods.ReleaseDC(new HandleRef(), new HandleRef(null, hScreenDC)); 

            if (result == false) 
            {
                UnsafeNativeMethods.HRESULT.Check(Marshal.GetHRForLastWin32Error());
            }
 
            return hWnd;
        } 
 
        /// 
        ///     Critical: Call SetActiveWindow to make sure the fade out animation is visible (if a fade out is specified) 
        ///     PublicOK: Only the splash screen window can be activated.
        ///               This class is not available in partial trust.
        /// 
        [SecurityCritical] 
        public void Close(TimeSpan fadeoutDuration)
        { 
            object result = null; 
            if (_dispatcher != null)
            { 
                if (_dispatcher.CheckAccess())
                {
                    result = CloseInternal(fadeoutDuration);
                } 
                else
                { 
                    result = _dispatcher.Invoke(DispatcherPriority.Normal, (DispatcherOperationCallback)CloseInternal, fadeoutDuration); 
                }
            } 

            if (result != BooleanBoxes.TrueBox)
            {
                // If all else fails try to destroy the resources on this thread 
                // this will probably end up throwing but it will be the same
                // exception as the previous version. 
                DestroyResources(); 
            }
        } 


        private object CloseInternal(Object fadeOutArg)
        { 
            TimeSpan fadeoutDuration = (TimeSpan) fadeOutArg;
            if (fadeoutDuration <= TimeSpan.Zero) 
            { 
                DestroyResources();
                return BooleanBoxes.TrueBox; 
            }

            // In the case where the developer has specified AutoClose=True and then calls
            // Close(non_zero_timespan) before the auto close operation is dispatched we begin 
            // the fadeout immidiately and ignore the later call to close.
            if (_dt != null || _hwnd == null) 
            { 
                return BooleanBoxes.TrueBox;
            } 

            // by default close gets called as soon as the first application window is created
            // since it will have become the active window we need to steal back the active window
            // status so that the fade out animation is visible. 
            IntPtr prevHwnd = UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, _hwnd));
            if (prevHwnd == IntPtr.Zero) 
            { 
                // SetActiveWindow fails (returns NULL) if the application is not in the foreground.
                // If this is the case, don't bother animating the fade out. 
                DestroyResources();
                return BooleanBoxes.TrueBox;
            }
 
            _dt = new DispatcherTimer();
            _dt.Interval = TimeSpan.FromMilliseconds(30); // shoot for ~30 fps 
            _fadeoutDuration = fadeoutDuration; 
            _fadeoutEnd = DateTime.UtcNow + _fadeoutDuration;
            _dt.Tick += new EventHandler(Fadeout_Tick); 
            _dt.Start();

            return BooleanBoxes.TrueBox;
        } 

        ///  
        /// Critical: Calls UpdateLayeredWindow to set a new opacity. 
        /// TreatAsSafe: The layered window is not exposed to the user for tampering and setting the opacity of
        ///              the splash screen is not dangerous. 
        ///              This class is not available in partial trust.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void Fadeout_Tick(object unused, EventArgs args) 
        {
            DateTime dtNow = DateTime.UtcNow; 
            if (dtNow >= _fadeoutEnd) 
            {
                DestroyResources(); 
            }
            else
            {
                double progress = (_fadeoutEnd - dtNow).TotalMilliseconds / _fadeoutDuration.TotalMilliseconds; 
                _blendFunc.SourceConstantAlpha = (byte)(255 * progress);
                UnsafeNativeMethods.UpdateLayeredWindow(_hwnd, IntPtr.Zero, null, null, IntPtr.Zero, null, 0, ref _blendFunc, NativeMethods.ULW_ALPHA); 
            } 
        }
 
        /// 
        ///     Critical: Calls into UnsafeNativeMethods to free resources
        ///     TreatAsSafe: Only frees resources allocated by this class and stored privately.
        ///                  Checks that resource pointers are valid before attempting to free them. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void DestroyResources() 
        {
            if (_dt != null) 
            {
                _dt.Stop();
                _dt = null;
            } 
            if (_hwnd != IntPtr.Zero)
            { 
                HandleRef hwnd = new HandleRef(null, _hwnd); 
                if (UnsafeNativeMethods.IsWindow(hwnd))
                { 
                    UnsafeNativeMethods.IntDestroyWindow(hwnd);
                }
                _hwnd = IntPtr.Zero;
            } 
            if (_hBitmap != null && !_hBitmap.IsClosed)
            { 
                UnsafeNativeMethods.DeleteObject(_hBitmap.MakeHandleRef(null).Handle); 
                _hBitmap.Close();
                _hBitmap = null; 
            }
            if (_wndClass != 0)
            {
                // Attempt to unregister the window class.  If the application has a second 
                // splash screen which is still open this call will fail.  That's OK.
                if (UnsafeNativeMethods.IntUnregisterClass(new IntPtr(_wndClass), _hInstance) != 0) 
                { 
                    _defWndProc = null; // Can safely release the wndproc delegate when there are no more splash screen instances
                } 
                _wndClass = 0;
            }
            if (_resourceManager != null)
            { 
                _resourceManager.ReleaseAllResources();
            } 
        } 

        ///  
        ///     Critical:   Calls out to WIC to decode the image buffer.
        ///                 Calls out to several other UnsafeNativeMethods to get DC and create a DDB.
        /// 
        [SecurityCritical] 
        private bool CreateLayeredWindowFromImgBuffer(IntPtr pImgBuffer, long cImgBufferLen, bool topMost)
        { 
            bool bSuccess = false; 
            IntPtr pImagingFactory = IntPtr.Zero;
            IntPtr pDecoder = IntPtr.Zero; 
            IntPtr pIStream = IntPtr.Zero;
            IntPtr pDecodedFrame = IntPtr.Zero;
            IntPtr pBitmapSourceFormatConverter = IntPtr.Zero;
            IntPtr pBitmapFlipRotator = IntPtr.Zero; 

            try 
            { 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateImagingFactory(UnsafeNativeMethods.WIC.WINCODEC_SDK_VERSION, out pImagingFactory)); 

                // Use the WIC stream class to wrap the unmanaged pointer
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateStream(pImagingFactory, out pIStream)); 

                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeStreamFromMemory(pIStream, pImgBuffer, (uint)cImgBufferLen)); 

                // Create an object that will decode the encoded image 
                Guid vendor = Guid.Empty;
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateDecoderFromStream(pImagingFactory, pIStream,
                                                                    ref vendor, 0, out pDecoder)); 

                // Get the frame from the decoder. Most image formats have only a single frame, in the case 
                // of animated gifs we are ok with only displaying the first frame of the animation. 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.GetFrame(pDecoder, 0, out pDecodedFrame)); 

                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateFormatConverter(pImagingFactory, out pBitmapSourceFormatConverter));
 
                // Convert the image from whatever format it is in to 32bpp premultiplied alpha BGRA
                Guid pixelFormat = UnsafeNativeMethods.WIC.WICPixelFormat32bppPBGRA; 
                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeFormatConverter(pBitmapSourceFormatConverter, pDecodedFrame,
                                                                      ref pixelFormat, 0 /*DitherTypeNone*/, IntPtr.Zero, 
                                                                      0, UnsafeNativeMethods.WIC.WICPaletteType.WICPaletteTypeCustom));
                // Reorient the image
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CreateBitmapFlipRotator(pImagingFactory, out pBitmapFlipRotator)); 

                UnsafeNativeMethods.HRESULT.Check( 
                    UnsafeNativeMethods.WIC.InitializeBitmapFlipRotator(pBitmapFlipRotator, pBitmapSourceFormatConverter, 
                                                                        UnsafeNativeMethods.WIC.WICBitmapTransformOptions.WICBitmapTransformFlipVertical));
                Int32 width, height; 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.GetBitmapSize(pBitmapFlipRotator, out width, out height));

                Int32 stride = width * 4; 

                // initialize the bitmap header 
                MS.Win32.NativeMethods.BITMAPINFO bmInfo = new MS.Win32.NativeMethods.BITMAPINFO(width, height, 32 /*bpp*/); 
                bmInfo.bmiHeader_biCompression = MS.Win32.NativeMethods.BI_RGB;
                bmInfo.bmiHeader_biSizeImage = (int)(stride * height); 

                // Create a 32bpp DIB.  This DIB must have an alpha channel for UpdateLayeredWindow to succeed.
                IntPtr pBitmapBits = IntPtr.Zero;
                _hBitmap = UnsafeNativeMethods.CreateDIBSection(new HandleRef(), ref bmInfo, 0 /* DIB_RGB_COLORS*/, ref pBitmapBits, IntPtr.Zero, 0); 

                // Copy the decoded image to the new buffer which backs the HBITMAP 
                Int32Rect rect = new Int32Rect(0, 0, width, height); 
                UnsafeNativeMethods.HRESULT.Check(
                    UnsafeNativeMethods.WIC.CopyPixels(pBitmapFlipRotator, ref rect, stride, stride * height, pBitmapBits)); 

                _hwnd = CreateWindow(_hBitmap, width, height, topMost);

                bSuccess = true; 
            }
            finally 
            { 
                if (pImagingFactory != IntPtr.Zero)
                { 
                    Marshal.Release(pImagingFactory);
                }
                if (pDecoder != IntPtr.Zero)
                { 
                    Marshal.Release(pDecoder);
                } 
                if (pIStream != IntPtr.Zero) 
                {
                    Marshal.Release(pIStream); 
                }
                if (pDecodedFrame != IntPtr.Zero)
                {
                    Marshal.Release(pDecodedFrame); 
                }
                if (pBitmapSourceFormatConverter != IntPtr.Zero) 
                { 
                    Marshal.Release(pBitmapSourceFormatConverter);
                } 
                if (pBitmapFlipRotator != IntPtr.Zero)
                {
                    Marshal.Release(pBitmapFlipRotator);
                } 

                if (bSuccess == false) 
                { 
                    DestroyResources(); // cleans up _hwnd and _hBitmap
                } 
            }

            return bSuccess;
        } 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK