WinApi窗口创建

时间:2015-02-08 07:08:59

标签: c# winapi

编辑1:改进了错误检查,如果仍然存在隐藏错误,仍然不清楚。

我一直在尝试使用来自C#的对user32.dll的P / Invoke调用来创建自定义窗口。然而,我的问题是,在最低级别的错误报告中,我无法确定确切的问题。我相当肯定这个问题源于我对WNDCLASSEX的定义或实例化,因为用一个系统来替换自定义类,例如" MDIClient"解决错误。

主要文件:

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.ComponentModel;

namespace CoreLib
{
    /// <summary>
    /// Basic window class.
    /// </summary>
    public class Window
    {
        /// <summary>
        /// Checks for an error and reports it and it's location.
        /// </summary>
        /// <param name="location"></param>
        private static void checkError(string location)
        {
            int error = Marshal.GetLastWin32Error();
            if(error != 0)//if not NO_ERROR
            {
                System.Console.WriteLine(location + " " + new Win32Exception(error).Message + " " + error);
            }
        }

        //various constants
        private const int CS_HREDRAW = 0x0002;
        private const int CS_VREDRAW = 0x0001;
        private const uint WS_OVERLAPPED = 0x0;
        private const uint WS_CAPTION = 0xC00000;
        private const uint WS_SYSMENU = 0x80000;
        private const uint WS_SIZEFRAME = 0x40000;
        private const uint WS_MINIMIZEBOX = 0x20000;
        private const uint WS_MAXIMIZEBOX = 0x10000;
        private const uint WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_SIZEFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
        private const int WINDOW_SHOW_NORMAL = 1;

        //the static hinstance
        private static IntPtr hInstance = Marshal.GetHINSTANCE(typeof(Window).Module);//System.Diagnostics.Process.GetCurrentProcess().Handle;
        //the pointer to the window object
        private IntPtr windowPointer;

        /// <summary>
        /// Creates a new Window with the given title.
        /// </summary>
        /// <param name="title"></param>
        public Window(string title)
        {
            //create a class for the window
            WNDCLASSEX clazz = new WNDCLASSEX();
            //initialize the class
            clazz.init(title, null);

            //register
            ushort atom = RegisterClassEx(ref clazz);
            if(atom == 0) checkError("RegisterClassEx");

            //create window
            windowPointer = CreateWindowEx(0, (uint)atom, title, WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, IntPtr.Zero, IntPtr.Zero, hInstance, IntPtr.Zero);
            if(windowPointer == IntPtr.Zero) checkError("CreateWindowEx");
            //show window
            ShowWindow(windowPointer, WINDOW_SHOW_NORMAL);
            checkError("ShowWindow");
            //update window
            bool result = UpdateWindow(windowPointer);
            if(!result) checkError("UpdateWindow");
        }

        /// <summary>
        /// The message loop.
        /// </summary>
        public void run()
        {
            sbyte code;
            Message message;

            while(true)
            {
                //get the next message
                code = GetMessage(out message, IntPtr.Zero, 0, 0);
                //if 0, we're done
                if(code == 0)
                {
                    return;
                }else//if -1, we have error
                if(code == -1)
                {
                    checkError("GetMessage");
                }else
                {
                    //translate
                    TranslateMessage(ref message);
                    //dispatch
                    DispatchMessage(ref message);
                }
            }
        }

        /// <summary>
        /// Relevant message codes
        /// </summary>
        enum MessageCode : uint
        {
            DESTROY = 0x0002,
            SIZE = 0x0005,
            PAINT = 0x000F,
        }

        /// <summary>
        /// Main Message handler.
        /// </summary>
        [AllowReversePInvokeCalls]
        private static IntPtr WindowEvent(IntPtr window, uint message, IntPtr wParam, IntPtr lParam)
        {
            switch ((MessageCode)message)
            {
                /*case MessageCode.PAINT:
                    return IntPtr.Zero;
                case MessageCode.SIZE:
                    return IntPtr.Zero;*/
                case MessageCode.DESTROY:
                    PostQuitMessage(0);
                    return IntPtr.Zero;
                default:
                    //pass off to default handling
                    IntPtr result = DefWindowProc(window, message, wParam, lParam);
                    //checkError("DefWindowProc");
                    return result;
            }
        }

        //user32 methods
        [DllImport("user32.dll", SetLastError = true)]
        private static extern sbyte GetMessage(out Message message, IntPtr window, uint wMsgFilterMin, uint wMsgFilterMax);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool TranslateMessage([In] ref Message message);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr DispatchMessage([In] ref Message message);
        [DllImport("user32.dll")]
        private static extern void PostQuitMessage(int exitCode);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr DefWindowProc(IntPtr window, uint message, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.U2)]
        private static extern ushort RegisterClassEx([In] ref WNDCLASSEX clazz);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr CreateWindowEx(uint styleEx, uint clazz, string windowName, uint style, int x, int y, int width, int height, IntPtr parent, IntPtr menu, IntPtr hInst, IntPtr param);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool ShowWindow(IntPtr window, int showCommands);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool UpdateWindow(IntPtr window);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr LoadIcon(IntPtr hInst, string iconName);

        //message handler delegate
        private delegate IntPtr EventHandler(IntPtr window, uint message, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// Message structure
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct Message
        {
            public IntPtr window;
            public uint code;
            public UIntPtr wParam;
            public UIntPtr lParam;
            public uint time;
            public POINT point;
        }

        /// <summary>
        /// Point structure
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int x;
            public int y;
        }

        /// <summary>
        /// Extended window class structure
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct WNDCLASSEX
        {
            [MarshalAs(UnmanagedType.U4)]
            public int size;
            [MarshalAs(UnmanagedType.U4)]
            public int style;
            public IntPtr wndProc;
            public int clsExtra;
            public int wndExtra;
            public IntPtr hInst;
            public IntPtr icon;
            public IntPtr cursor;
            public IntPtr background;
            public string menuName;
            public string className;
            public IntPtr smIcon;

            public void init(string name, string iconName)
            {
                size = Marshal.SizeOf(this);//set size
                style = CS_HREDRAW | CS_VREDRAW;//set style 
                wndProc = Marshal.GetFunctionPointerForDelegate((Delegate)(EventHandler)WindowEvent);//set the pointer to the message delegate
                clsExtra = 0;//unused
                wndExtra = 0;//unused
                hInst = hInstance;//set hinstance
                if(string.IsNullOrEmpty(iconName))//if icon not provided, use default
                {
                    icon = SystemIcons.Application.Handle;
                }else//else load given
                {
                    icon = LoadIcon(hInstance, iconName);
                }
                cursor = System.Windows.Forms.Cursors.Default.Handle;//use default cursor
                background = IntPtr.Zero;//use default background
                menuName = null;//no menu
                className = name + "Class";//set class name
                smIcon = IntPtr.Zero;//default small icon
            }
        }
    }
}

执行文件:

using System;
using UtilLib;

namespace CoreLib
{
    public class Runner
    {
        static void Main(string[] args)
        {
            Window window = new Window("Tester");
            window.run();
        }
    }
}

控制台输出:

RegisterClassEx The system cannot find the file specified 2
CreateWindowEx The system cannot find the file specified 2
ShowWindow Cannot find window class 1407
UpdateWindow Invalid window handle 1400

我认为代码很可能存在多个复合问题。

0 个答案:

没有答案