代码之家  ›  专栏  ›  技术社区  ›  Tom Wright

在表单应用程序中能否实现WPF风格的启动屏幕?

  •  1
  • Tom Wright  · 技术社区  · 15 年前

    在visualstudio10项目中使用资源时,我遇到了一个名为“splashscreen”的构建操作,这使我在 neat splash screen capabilities of WPF .

    making a splash screen in Windows Forms ,但这是一种不同的方法:WinForms版本只是在主窗体初始化时显示初始屏幕,而不是在应用程序加载之前使用本机代码加载初始屏幕。

    有没有办法在WinForms应用程序中实现这种高级启动屏幕?

    2 回复  |  直到 15 年前
        1
  •  4
  •   Dennis    15 年前

    对。在WPF应用程序与.NET3.5SP1打包之前,我为它做了一个实现。

    基本上,您可以在加载程序集和初始化应用程序时创建一个本机Win32窗口并显示BMP图像。您可以使用其他图像格式,但BMP是首选,因为它需要加载的库最少。

    一个快速的google“创建本地splash窗口”出现了几篇文章。我发现(快速扫描)最全面的是布拉德利·格兰杰: Displaying a Splash Screen with C++ . 这篇文章是为WPF写的,但是概念是一样的:创建一个本地窗口,启动 你的

    明天我将在工作中查看实现的源代码,并用示例更新我的答案。

    在此之前,谷歌和研究的许多例子已经在那里开始。

    正如所承诺的,下面是一个实现启动屏幕的完整示例(这里有一点)。

    using System;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using System.Windows.Interop;
    
    namespace SplashScreen
    {
    
        public class SplashScreenManager
        {
            static SplashScreen _current = null;
    
            static SplashScreenManager() {}
            SplashScreenManager() { }
    
            public static SplashScreen Create(Module module, int resourceID)
            {
                if (_current != null)
                {
                    _current.Close();
                    _current.Dispose();
                }
    
                _current = new SplashScreen(module, resourceID);
                return _current;
            }
    
            public static void Close()
            {
                if (_current == null)
                    return;
    
                _current.Close();
                _current.Dispose();
                _current = null;
            }
    
            public static SplashScreen Current
            {
                get { return _current; }
            }
    
        }
    
        public class SplashScreen : IDisposable
        {                
            static bool IsClassRegistered = false;
            static string WindowClassName = "SplashScreenWindowClass";
    
            IntPtr _bitmapHandle = IntPtr.Zero;
            int _bitmapHeight;
            int _bitmapWidth;
            bool _isClosed;
    
            UnsafeNativeMethods.WndProc _splashWindowProcedureCallback;
    
            IntPtr _windowHandle = IntPtr.Zero;
    
            [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
            internal SplashScreen(Module module, int resourceID)
            {
                _bitmapHandle = UnsafeNativeMethods.LoadBitmap(Marshal.GetHINSTANCE(module), new IntPtr(resourceID));
                _splashWindowProcedureCallback = new UnsafeNativeMethods.WndProc(SplashWindowProcedure);
            }
    
            public void Close()
            {
                if (_isClosed)
                    return;
    
                _isClosed = true;
                UnsafeNativeMethods.PostMessage(new HandleRef(this, _windowHandle), 0x10, IntPtr.Zero, IntPtr.Zero);
                if (_bitmapHandle != IntPtr.Zero)
                {
                    UnsafeNativeMethods.DeleteObject(_bitmapHandle);
                    _bitmapHandle = IntPtr.Zero;
                }
            }
    
            public void Close(IntPtr handle)
            {
                if (_windowHandle != IntPtr.Zero)
                    UnsafeNativeMethods.SetForegroundWindow(handle);
    
                Close();
            }
    
            void CreateWindow()
            {
                if (!IsClassRegistered)
                    RegisterClass();
    
                if (IsClassRegistered)
                {
                    CreateWindowInternal();
                    if (_windowHandle != IntPtr.Zero)
                        UnsafeNativeMethods.ShowWindow(_windowHandle, 5);
    
                }
            }
    
            public void Dispose()
            {
                Dispose(true);
            }
    
            protected virtual void Dispose(bool disposing)
            {
                Close(IntPtr.Zero);
                GC.SuppressFinalize(this);
            }
    
            void GetBitmapDimensions()
            {
                int cb = Marshal.SizeOf(typeof(UnsafeNativeMethods.BITMAP));
                IntPtr lpvObject = Marshal.AllocCoTaskMem(cb);
                UnsafeNativeMethods.GetObject(_bitmapHandle, cb, lpvObject);
                UnsafeNativeMethods.BITMAP bitmap = (UnsafeNativeMethods.BITMAP)Marshal.PtrToStructure(lpvObject, typeof(UnsafeNativeMethods.BITMAP));
                _bitmapWidth = bitmap.bmWidth;
                _bitmapHeight = bitmap.bmHeight;
                Marshal.FreeCoTaskMem(lpvObject);
            }
    
            void OnPaint(IntPtr hdc)
            {
                if (_bitmapHandle != IntPtr.Zero)
                {
                    IntPtr ptr = UnsafeNativeMethods.CreateCompatibleDC(hdc);
                    IntPtr hgdiobj = UnsafeNativeMethods.SelectObject(ptr, _bitmapHandle);
                    UnsafeNativeMethods.BitBlt(hdc, 0, 0, _bitmapWidth, _bitmapHeight, ptr, 0, 0, 0xcc0020);
                    UnsafeNativeMethods.SelectObject(ptr, hgdiobj);
                    UnsafeNativeMethods.DeleteDC(ptr);
                }
            }
    
            void CreateWindowInternal()
            {
                int systemMetrics = UnsafeNativeMethods.GetSystemMetrics(0);
                int num4 = UnsafeNativeMethods.GetSystemMetrics(1);
                uint dwStyle = 0x80000000;
                uint dwExStyle = 0x188;
                IntPtr moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);
                IntPtr desktopWindow = UnsafeNativeMethods.GetDesktopWindow();
                _windowHandle = UnsafeNativeMethods.CreateWindowEx(dwExStyle, WindowClassName, "", dwStyle, (systemMetrics - _bitmapWidth) / 2, (num4 - _bitmapHeight) / 2, _bitmapWidth, _bitmapHeight, desktopWindow, IntPtr.Zero, moduleHandle, IntPtr.Zero);
            }
    
            void RegisterClass()
            {
                IntPtr moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);
                UnsafeNativeMethods.WNDCLASSEX lpwcx = new UnsafeNativeMethods.WNDCLASSEX();
                lpwcx.cbSize = (uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.WNDCLASSEX));
                lpwcx.cbClsExtra = 0;
                lpwcx.cbWndExtra = 0;
                lpwcx.hbrBackground = IntPtr.Zero;
                lpwcx.hCursor = IntPtr.Zero;
                lpwcx.hIcon = IntPtr.Zero;
                lpwcx.hIconSm = IntPtr.Zero;
                lpwcx.hInstance = moduleHandle;
                lpwcx.lpfnWndProc = _splashWindowProcedureCallback;
                lpwcx.lpszClassName = WindowClassName;
                lpwcx.lpszMenuName = null;
                lpwcx.style = 0;
                if (UnsafeNativeMethods.RegisterClassExW(ref lpwcx) != 0)
                {
                    IsClassRegistered = true;
                }
            }
    
            public void Show()
            {
                if (_windowHandle == IntPtr.Zero)
                {
                    Thread thread = new Thread(new ThreadStart(ThreadMethod));
                    thread.IsBackground = true;
                    thread.Start();
                }
            }
    
            [SuppressUnmanagedCodeSecurity]
            IntPtr SplashWindowProcedure(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
            {
                if (msg == 15)
                {
                    UnsafeNativeMethods.PAINTSTRUCT lpPaint = new UnsafeNativeMethods.PAINTSTRUCT();
                    IntPtr hdc = UnsafeNativeMethods.BeginPaint(hWnd, out lpPaint);
                    OnPaint(hdc);
                    UnsafeNativeMethods.EndPaint(hWnd, ref lpPaint);
                    return IntPtr.Zero;
                }
    
                return UnsafeNativeMethods.DefWindowProc(hWnd, msg, wParam, lParam);
            }
    
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            void ThreadMethod()
            {
                if (_bitmapHandle != IntPtr.Zero)
                {
                    GetBitmapDimensions();
                    CreateWindow();
                    MSG msg = new MSG();
                    while (UnsafeNativeMethods.GetMessage(ref msg, _windowHandle, 0, 0) > 0)
                    {
                        UnsafeNativeMethods.TranslateMessage(ref msg);
                        UnsafeNativeMethods.DispatchMessage(ref msg);
                    }
                    _windowHandle = IntPtr.Zero;
                    GC.KeepAlive(this);
                }
            }
    
        }
    
        [SuppressUnmanagedCodeSecurity]
        internal sealed class UnsafeNativeMethods
        {
            // Fields
            internal const int GWL_EXSTYLE = -20;
            public const int LOGPIXELSX = 0x58;
            public const int LOGPIXELSY = 90;
            internal const uint MB_ICONASTERISK = 0x40;
            internal const uint MB_ICONERROR = 0x10;
            internal const uint MB_ICONEXCLAMATION = 0x30;
            internal const uint MB_ICONHAND = 0x10;
            internal const uint MB_ICONINFORMATION = 0x40;
            internal const uint MB_ICONQUESTION = 0x20;
            internal const uint MB_ICONWARNING = 0x30;
            internal const uint MB_OK = 0;
            internal const uint MB_OKCANCEL = 1;
            internal const uint MB_SETFOREGROUND = 0x10000;
            internal const uint MB_YESNO = 4;
            internal const uint MB_YESNOCANCEL = 3;
            internal const int SM_CXSCREEN = 0;
            internal const int SM_CYSCREEN = 1;
            public const int SPI_GETWORKAREA = 0x30;
            internal const uint SRCCOPY = 0xcc0020;
            public const int SW_HIDE = 0;
            internal const int SW_SHOW = 5;
            public const int SW_SHOWMAXIMIZED = 3;
            public const int SW_SHOWMINIMIZED = 2;
            public const int SW_SHOWNORMAL = 1;
            internal const int WM_CLOSE = 0x10;
            internal const uint WS_EX_TOOLWINDOW = 0x80;
            internal const uint WS_EX_TOPMOST = 8;
            internal const uint WS_EX_TRANSPARENT = 0x20;
            internal const uint WS_EX_WINDOWEDGE = 0x100;
            internal const uint WS_POPUP = 0x80000000;
    
            UnsafeNativeMethods() {}
    
            [DllImport("user32.dll")]
            public static extern IntPtr WindowFromPoint(POINT Point);
            [DllImport("user32.dll")]
            public static extern IntPtr ChildWindowFromPoint(IntPtr hWndParent, POINT Point);
            [DllImport("user32.dll")]
            public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);
            [DllImport("user32.dll")]
            internal static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("gdi32.dll")]
            internal static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
            [DllImport("gdi32.dll")]
            internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
            [DllImport("user32.dll", EntryPoint = "CreateWindowExW", CharSet = CharSet.Unicode)]
            internal static extern IntPtr CreateWindowEx(uint dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
            [DllImport("user32.dll")]
            internal static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("gdi32.dll")]
            internal static extern bool DeleteDC(IntPtr hdc);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("gdi32.dll")]
            internal static extern bool DeleteObject(IntPtr hObject);
            [DllImport("user32.dll")]
            internal static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            internal static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);
            [DllImport("user32.dll")]
            public static extern IntPtr GetDC(IntPtr hWnd);
            [DllImport("user32.dll")]
            internal static extern IntPtr GetDC(HandleRef hWnd);
            [DllImport("user32.dll")]
            internal static extern IntPtr GetDesktopWindow();
            [DllImport("gdi32.dll")]
            public static extern int GetDeviceCaps(IntPtr hDC, int index);
            [DllImport("user32.dll", EntryPoint = "GetMessageW", CharSet = CharSet.Unicode, ExactSpelling = true)]
            internal static extern int GetMessage([In, Out] ref MSG msg, IntPtr hWnd, int uMsgFilterMin, int uMsgFilterMax);
            [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", CharSet = CharSet.Unicode)]
            internal static extern IntPtr GetModuleHandle(string lpModuleName);
            [DllImport("gdi32.dll")]
            internal static extern int GetObject(IntPtr hgdiobj, int cbBuffer, IntPtr lpvObject);
            [DllImport("user32.dll")]
            internal static extern int GetSystemMetrics(int nIndex);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            internal static extern int GetWindowLong(IntPtr handle, int index);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            public static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);
            [DllImport("user32.dll", EntryPoint = "LoadBitmapW", CharSet = CharSet.Unicode)]
            internal static extern IntPtr LoadBitmap(IntPtr hInstance, IntPtr lpBitmapName);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
            [return: MarshalAs(UnmanagedType.U2)]
            [DllImport("user32.dll")]
            internal static extern short RegisterClassExW([In] ref WNDCLASSEX lpwcx);
            [DllImport("user32.dll")]
            public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
            [DllImport("gdi32.dll")]
            internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            internal static extern bool SetForegroundWindow(IntPtr hWnd);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            internal static extern int SetWindowLong(IntPtr handle, int index, int dwNewLong);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            public static extern bool SystemParametersInfo(int nAction, int nParam, ref RECT rc, int nUpdate);
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("user32.dll")]
            internal static extern bool TranslateMessage([In] ref MSG lpMsg);
    
            [StructLayout(LayoutKind.Sequential)]
            internal struct BITMAP
            {
                public int bmType;
                public int bmWidth;
                public int bmHeight;
                public int bmWidthBytes;
                public ushort bmPlanes;
                public ushort bmBitsPixel;
                public IntPtr bmBits;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            internal struct PAINTSTRUCT
            {
                public IntPtr hdc;
                public bool fErase;
                public UnsafeNativeMethods.RECT rcPaint;
                public bool fRestore;
                public bool fIncUpdate;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
                public byte[] rgbReserved;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct POINT
            {
                public int X;
                public int Y;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            internal struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct WINDOWPLACEMENT
            {
                public int Length;
                public int Flags;
                public int ShowCmd;
                public UnsafeNativeMethods.POINT MinPosition;
                public UnsafeNativeMethods.POINT MaxPosition;
                public UnsafeNativeMethods.RECT NormalPosition;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            internal struct WNDCLASSEX
            {
                public uint cbSize;
                public uint style;
                public UnsafeNativeMethods.WndProc lpfnWndProc;
                public int cbClsExtra;
                public int cbWndExtra;
                public IntPtr hInstance;
                public IntPtr hIcon;
                public IntPtr hCursor;
                public IntPtr hbrBackground;
                public string lpszMenuName;
                public string lpszClassName;
                public IntPtr hIconSm;
            }
    
            internal delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
        }
    
    }
    
        2
  •  0
  •   Rowland Shaw    15 年前

    为此可以使用非WPF表单,而且工作起来非常愉快。另外,这也是VS2008的一个特性。