【发布时间】:2019-04-29 20:24:24
【问题描述】:
我目前正在编写自定义游戏引擎(用于自学)并研究窗口系统。我需要创建基本的操作系统窗口(这样我以后可以将其链接为 DirectX 的设备或为 OpenGL 创建上下文等)。我找到了一个使用 C# 创建 Win32 窗口的示例,因此我将其用作原型(示例代码在我的机器上正常工作),但是源代码就像一个单独的程序一样,我需要将它作为一个类来实现,从中我可以获得一个 IntPtr 来创建窗口。
我编写了自己的 Win32Window 类,实现了所有必需的功能。然后,我使用另一个项目对其进行了测试(我正在编写这个类作为我的游戏引擎 dll 的一部分),但它无法创建窗口。 涉及该主题的另一个问题(在 Stackoverflow 和其他论坛上)有不同的问题,这些问题来自使用我不需要的 winApi 功能(如控件和其他东西)或注册窗口类和创建窗口的错误顺序。
正如标题所说,我发现 CreateWindowEx 返回 null。
Marshal.GetLastWin32Error 说 CreateWindowEx 找不到注册的类。
我尝试使用变量字符串代替 ClassName,所以我不会遗漏名称。
我尝试使用带有 IntPtr 的 CreateWindowEx 的重载版本来注册类。
他们都没有工作。
WinApi 的所有托管代码均取自 Pinvoke.com 和 MSDN 文档。
这个问题绝对不是因为没有给 RegisterClassEx 和 CreateWindowEx 提供一个实际的 hInstance 指针而不是 IntPtr.Zero。
这是窗口类代码:
public sealed class Win32Window : NativeWindow // NativeWindow is my engine's window API containing some size, name and pointer properties
{
-- Some properties and fields routine --
//Constructor takes job of registering class
public Win32Window(string WindowName, WndProc CallBack)
{
this.WindowName = WindowName;
this.Callback = CallBack;
this.wc = WNDCLASSEX.Build();
this.wc.style = (int)(CS.HRedraw | CS.VRedraw);
this.wc.lpfnWndProc = this.Callback;
this.wc.hInstance = IntPtr.Zero;
this.wc.hCursor = LoadCursor(IntPtr.Zero, (int)IDC.Arrow);
this.wc.hbrBackground = IntPtr.Zero;
this.wc.lpszClassName = ClassName;
this.wc.cbClsExtra = 0;
this.wc.cbWndExtra = 0;
this.wc.hIcon = LoadIcon(IntPtr.Zero,(IntPtr)IDI_APPLICATION);
this.wc.lpszMenuName = null;
this.wc.hIconSm = IntPtr.Zero;
ClassPtr = (IntPtr)RegisterClassEx(ref this.wc);
Console.WriteLine(ClassPtr); //Outputs negative integer, so i can conclude this part works properly
}
public void Create()
{
this.WindowHandle = CreateWindowEx(0,
ClassName,
this.WindowName,
(uint)WS.OverlappedWindow,
this.PosX,
this.PosY,
this.Width,
this.Height,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
Console.WriteLine($"{WindowHandle == IntPtr.Zero} {Marshal.GetLastWin32Error()}"); //Outputs "True 1407"
}
public void Show()
{
ShowWindow(this.WindowHandle, 1);
}
public void Iterate()
{
while (GetMessage(out msg, IntPtr.Zero, 0, 0) > 0)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
--- Some [DllImport] routine ---
}
这是TestWindow类代码:
public class TestWindow
{
Win32Window.WndProc callback;
Win32Window Window;
private static IntPtr WndProc(IntPtr hWnd, Win32Window.WM message, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine(message);
switch (message)
{
case Win32Window.WM.Destroy:
Win32Window.PostQuitMessage(0);
return IntPtr.Zero;
default:
return (Win32Window.DefWindowProc(hWnd, message, wParam, lParam));
}
}
public TestWindow()
{
callback = WndProc;
Window = new Win32Window("TestWindow", callback);
Window.Create();
Window.Show();
Window.Iterate();
}
}
测试控制台应用的 Main 方法只是创建一个新的 TestWindow 实例。
【问题讨论】:
-
错误信息似乎很清楚。尝试调试。检查您创建时使用的类名称是否与您注册时使用的名称匹配。