c# - C# 和 PInvoke Winapi 程序挂起
问题描述
所以我正在尝试使用 PInvoke 制作一个 winapi 应用程序。到目前为止,我已经能够打开一个窗口,但从那里,我似乎无法完成这项WndProc
工作。现在,应用程序启动了,但它既不会响应调整大小,也不会响应移动或任何东西,除了悬停在控制按钮上方。
WindowLL.cs:
public delegate long WndProc(IntPtr hWnd, uint message, byte wParam, long lParam);
public static unsafe class WindowLL
{
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern ushort RegisterClassExA(ref WNDCLASSEX _class);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr CreateWindowExA(
uint extraStyle,
ushort className,
//[MarshalAs(UnmanagedType.LPWStr)]
//string className,
[MarshalAs(UnmanagedType.LPStr)]
string title,
uint style,
int x,
int y,
int width,
int height,
IntPtr parent,
IntPtr menu,
IntPtr instance,
IntPtr parameter
);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMessage(
out MSG lpMsg,
IntPtr hWnd,
uint wMsgFilterMin,
uint wMsgFilterMax
);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern uint DispatchMessage(ref MSG lpMsg);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern uint TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern long DefWindowProcA(
IntPtr hWnd,
uint Msg,
byte wParam,
long lParam
);
}
结构(分成不同的文件):
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public uint message;
public byte wParam;
public long lParam;
public short time;
public POINT pt;
public short lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public long X;
public long Y;
}
[StructLayout(LayoutKind.Sequential)]
public struct WNDCLASSEX
{
public uint cbSize;
public uint style;
public WndProc lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszClassName;
public IntPtr hIconSm;
}
程序.cs:
class Program
{
static long WndProc(IntPtr hWnd, uint message, byte wParam, long lParam)
{
return WindowLL.DefWindowProcA(hWnd, message, wParam, lParam);
}
static void Main(string[] args)
{
var winCalss = new WNDCLASSEX() {
lpszClassName = "test",
lpfnWndProc = WndProc,
cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)),
};
var classId = WindowLL.RegisterClassExA(ref winCalss);
var overlapped =
WindowStyle.Overlapped |
WindowStyle.Caption |
WindowStyle.SysMenu |
WindowStyle.ThickFrame |
WindowStyle.MinimizeBox |
WindowStyle.MaximizeBox;
IntPtr hWnd = WindowLL.CreateWindowExA(0,
classId, "test",
(uint)overlapped,
0, 0,
1280, 720,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero
);
WindowLL.ShowWindow(hWnd, (int)NCmdShow.Show);
while (WindowLL.GetMessage(out var msg, hWnd, 0, 0)) {
WindowLL.TranslateMessage(ref msg);
WindowLL.DispatchMessage(ref msg);
}
}
}
解决方案
你的结构大多是错误的。
wParam / lParam 都应该是 IntPtr,时间应该是 uint,点 x/y 应该是 int。
您甚至不需要自己编写它们,从框架中复制粘贴,MIT 许可证允许:
https://source.dot.net/#WindowsBase/System/Windows/Interop/MSG.cs,8a0b462145bdb8d8
还有一件事。您不应该使用 A 函数和结构,例如CreateWindowExA
. 这些是 Windows 95、98 和 Me 的兼容性垫片,这 3 个都在几十年前停产了。现代软件应该只使用 W 版本。作为一个很好的副作用,字符串编组更便宜,C# 字符串存储为 UTF-16,它与 W WinApi 函数预期的编码相匹配。
推荐阅读
- ios - Objective C 中的串行 API 调用
- python - Python Selenium 访问 Barchart 显示全部页面
- python - 试图为 y 轴数据选择多个列表项;获取 TypeError “列表索引必须是整数或切片,而不是元组”
- reactjs - 在 TypeScript 中,“我可以在没有道具的情况下调用的组件”怎么说?
- prolog - Prolog“切换”语句
- c# - 捕捉全局 MouseClick 然后重复它
- pandas - 如何删除列表中的空白空间并将更新的列表调整回 csv
- javascript - 如何使用控制台删除 onblur 甚至监听器?
- php - Laravel 自定义错误响应时间过长
- squeryl - NOT 和 OR 运算符在 Squeryl 中不起作用