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