gpt4 book ai didi

c# - 使用联合调用 PInvoke 结构时,使用 StructLayout( LayoutKind.Explicit ) 我做错了什么?

转载 作者:太空宇宙 更新时间:2023-11-03 22:25:26 31 4
gpt4 key购买 nike

下面是一个完整的程序。只要您不取消注释顶部的“#define BROKEN”,它就可以正常工作。中断是由于 PInvoke 未能正确编码联合。所讨论的 INPUT_RECORD 结构有许多子结构,可以根据 EventType 中的值使用这些子结构。

我不明白的是,当我只定义 KEY_EVENT_RECORD 的单个子结构时,它与偏移量 4 处的显式声明一起工作。但是当我在相同的偏移量处添加其他结构时结构的内容得到完全控制。

//UNCOMMENT THIS LINE TO BREAK IT:
//#define BROKEN

using System;
using System.Runtime.InteropServices;

class ConIOBroken
{
static void Main()
{
int nRead = 0;
IntPtr handle = GetStdHandle(-10 /*STD_INPUT_HANDLE*/);
Console.Write("Press the letter: 'a': ");

INPUT_RECORD record = new INPUT_RECORD();
do
{
ReadConsoleInputW(handle, ref record, 1, ref nRead);
} while (record.EventType != 0x0001/*KEY_EVENT*/);

Assert.AreEqual((short)0x0001, record.EventType);
Assert.AreEqual(true, record.KeyEvent.bKeyDown);
Assert.AreEqual(0x00000000, record.KeyEvent.dwControlKeyState & ~0x00000020);//strip num-lock and test
Assert.AreEqual('a', record.KeyEvent.UnicodeChar);
Assert.AreEqual((short)0x0001, record.KeyEvent.wRepeatCount);
Assert.AreEqual((short)0x0041, record.KeyEvent.wVirtualKeyCode);
Assert.AreEqual((short)0x001e, record.KeyEvent.wVirtualScanCode);
}

static class Assert { public static void AreEqual(object x, object y) { if (!x.Equals(y)) throw new ApplicationException(); } }

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ReadConsoleInputW(IntPtr hConsoleInput, ref INPUT_RECORD lpBuffer, int nLength, ref int lpNumberOfEventsRead);

[StructLayout(LayoutKind.Explicit)]
public struct INPUT_RECORD
{
[FieldOffset(0)]
public short EventType;
//union {
[FieldOffset(4)]
public KEY_EVENT_RECORD KeyEvent;
#if BROKEN
[FieldOffset(4)]
public MOUSE_EVENT_RECORD MouseEvent;
[FieldOffset(4)]
public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
[FieldOffset(4)]
public MENU_EVENT_RECORD MenuEvent;
[FieldOffset(4)]
public FOCUS_EVENT_RECORD FocusEvent;
//}
#endif
}

[StructLayout(LayoutKind.Sequential)]
public struct KEY_EVENT_RECORD
{
public bool bKeyDown;
public short wRepeatCount;
public short wVirtualKeyCode;
public short wVirtualScanCode;
public char UnicodeChar;
public int dwControlKeyState;
}

[StructLayout(LayoutKind.Sequential)]
public struct MOUSE_EVENT_RECORD
{
public COORD dwMousePosition;
public int dwButtonState;
public int dwControlKeyState;
public int dwEventFlags;
};

[StructLayout(LayoutKind.Sequential)]
public struct WINDOW_BUFFER_SIZE_RECORD
{
public COORD dwSize;
}

[StructLayout(LayoutKind.Sequential)]
public struct MENU_EVENT_RECORD
{
public int dwCommandId;
}

[StructLayout(LayoutKind.Sequential)]
public struct FOCUS_EVENT_RECORD
{
public bool bSetFocus;
}

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
}
}

更新:

对于那些自己担心结构声明的人:

  1. bool 被视为 32 位值
  2. 在数据上使用 offset(4) 的原因是允许 32 位结构对齐,从而防止并集从偏移量 2 开始。

同样,我的问题根本不是让 PInvoke 工作,而是试图找出为什么这些额外的结构(假设在相同的偏移量)通过简单地添加它们来收集数据。

最佳答案

我相信如果您将 bSetFocus 和 dwCommandId 设为 uint 类型,它会起作用。

以后,查看 PInvoke wiki以获得正确的签名。它通常是准确的,或者至少是一个很好的起点。

关于c# - 使用联合调用 PInvoke 结构时,使用 StructLayout( LayoutKind.Explicit ) 我做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1602487/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com