2010-06-29 6 views
1

En jouant avec des ressources dans mon projet de studio visuel 10, je suis tombé sur une action de construction appelée "Splash Screen", qui m'a conduit à trouver cet article sur le neat splash screen capabilities of WPF. Je trouve cet article MSDN sur making a splash screen in Windows Forms, mais c'est un autre type d'approche: plutôt que de charger l'écran de démarrage en utilisant du code natif avant le chargement de l'application, la version WinForms l'affiche simplement pendant l'initialisation du formulaire principal.Un écran de démarrage de style WPF peut-il être réalisé dans une application Forms?

Est-il possible de réaliser ce type supérieur de l'écran de démarrage dans une application WinForms?

Répondre

4

Oui. J'ai fait une implémentation pour notre application WPF avant qu'elle ne soit fournie avec .NET 3.5 SP1.

Fondamentalement, vous créez une fenêtre Win32 native et d'afficher une image BMP pendant que vous chargez les assemblages et initialisant votre application. Vous pouvez utiliser d'autres formats d'image, mais BMP est préféré car il nécessite le moins de bibliothèques chargées.

Un rapide Google pour « la création de la fenêtre de démarrage natif » est venu avec plusieurs articles. Le plus complet que j'ai trouvé (d'un balayage rapide) était par Bradley Grainger: Displaying a Splash Screen with C++. L'article a été écrit pour WPF à l'esprit, mais le concept est le même: créer une fenêtre native, lancer votre application, fermez la fenêtre.

je vais jeter un oeil à la source pour mon avenir la mise en œuvre au travail et mettre à jour ma réponse avec un exemple.

Jusque-là, Google et la recherche des nombreux exemples déjà là-bas pour commencer.

MISE À JOUR

Comme promis, voici un exemple complet de la mise en œuvre d'un écran de démarrage (il est un peu à elle).

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); 
    } 

} 
+0

Cela semble bon. Voir aussi la réinvention par Olson: http://www.olsonsoft.com/blogs/stefanolson/post/A-better-WPF-splash-screen.aspx –

+0

@Tom: Je lis en fait Olsons poster d'abord et suis les liens pour trouver L'article de Bradley. Je mettrai à jour ma réponse plus tard aujourd'hui quand j'aurai le temps. – Dennis

+0

@Tom: Mise à jour avec des exemples. – Dennis

0

Il est possible d'utiliser une forme non-WPF pour cela, et cela fonctionne très heureux. En aparté, c'était aussi une caractéristique de VS2008.

Questions connexes