Можно ли создать заставку в стиле WPF в приложении Forms? - PullRequest
1 голос
/ 29 июня 2010

Играя с ресурсами в моем проекте visual studio 10, я натолкнулся на действие по сборке под названием «Всплеск экрана», которое привело меня к поиску этой статьи о опрятных возможностях заставки WPF .

Охота вокруг, я нашел эту статью MSDN о создании заставки в Windows Forms , но это другой тип подхода: вместо загрузки заставки с использованием собственного кода перед загрузкой приложения, WinForms версия просто отображает ее, пока инициализируется основная форма.

Есть ли какой-нибудь способ добиться этого превосходного типа заставки в приложении WinForms?

Ответы [ 2 ]

4 голосов
/ 29 июня 2010

Да.Я сделал реализацию для нашего приложения WPF до того, как оно было упаковано с .NET 3.5 SP1.

По сути, вы создаете собственное окно Win32 и отображаете образ BMP во время загрузки сборок и инициализации приложения.Вы можете использовать другие форматы изображений, но BMP предпочтительнее, так как требует наименьшего количества загруженных библиотек.

Быстрый гугл для «создания собственного окна-заставки» содержит несколько статей.Самым полным из обнаруженных мной (из быстрого сканирования) был Брэдли Грейнджер: Отображение заставки с C ++ .Статья была написана для WPF, но концепция та же: создать собственное окно, запустить ваше приложение, закрыть окно.

Я посмотрю источник моей реализации завтра на работе и дополню свой ответ примерами.

До тех пор, Google и исследовать множество примеров, уже там, чтобы начать.

ОБНОВЛЕНИЕ

Как и обещано, ниже приведен полный примерреализации заставки (есть немного)

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 голосов
/ 29 июня 2010

Для этого можно использовать форму не-WPF, и она работает довольно счастливо.Кроме того, это была особенность и в VS2008.

...