编辑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
我认为代码很可能存在多个复合问题。