C# WinApi窗口创建

C# WinApi窗口创建,c#,winapi,C#,Winapi,编辑1:改进的错误检查,仍然不清楚是否仍然存在隐藏错误 我一直在尝试使用C中对user32.dll的p/Invoke调用来创建一个自定义窗口。然而,我的问题是,在错误报告级别最低的情况下,我无法确定确切的问题。我相当肯定这个问题源于我对WNDCLASSEX的定义或实例化,因为用系统类(如MDIClient)替换自定义类可以解决错误 主文件: using System; using System.Runtime.InteropServices; using System.Drawing; usin

编辑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
            }
        }
    }
}
和控制台输出:

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

我想代码很可能有多个复合问题。

Debug,Debug,Debug。找到主要的问题,如果你愿意的话,在这里提问。复制/粘贴您的整个代码并告诉人们查找问题是错误的。作为调试的第一步:您没有正确地检查错误返回。仅仅存在GetLastError值不足以表明发生了错误,因为无法保证后续函数将清除该值。您必须检查每个函数的返回值,只有在其中一个函数指示失败时才查找错误。例如,RegisterClassEx在失败时返回零。检查MSDN中每个函数的返回值。我想知道这是否是一个好的设计决策,尝试使用C和P/Invoke来创建自定义窗口。我认为编写一个C++模块来处理WiAPI API,然后与C.C.ZAZZ.IITTITLE,NULL进行接口是更好的。看起来不对。。在Win32中,不能用标题初始化WNDCLASS。您有两个问题。它从你从pinvoke.net网站得到的不可靠的pinvoke声明开始。这通常不是最好的地方找到好的,特别是没有人用过的那种。就像你用的那些。你的错误检查完全被破坏了。这种组合是相当致命的,当然,你没有机会做到这一点。NET引用源是找到好声明的好地方,它们每天被使用数十亿次。已经存在的包装器也是如此,比如NativeWindow。
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