想往剧情里塞点meta元素,需要有窗口移动的功能,但是Unity没有提供API
可以用到user32.dll里的GetActiveWindow(),SetWindowPos(),GetWindowRect(),
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
[DllImport("user32.dll", SetLastError=true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll", SetLastError=true)]
static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
static:非托管 DLL 的导出函数是全局原生函数,无 “类实例” 概念,必须声明为静态;
extern:标记该方法 “无托管实现体”,告诉编译器 “实现不在 C# 代码里,由 CLR 从外部 DLL 找”;
[DllImport]:给 CLR 提供调用非托管 DLL 的核心元数据(DLL 路径、导出函数名、调用约定等);
类的作用:仅作为 “逻辑容器”(C# 要求所有方法必须属于类 / 结构体),和非托管 DLL 无任何绑定关系
DllImport的设计适配 C/C++ 非托管 DLL:
数据类型匹配:CLR 自动完成 “托管类型↔非托管类型” 封送(如 C# int↔C/C++ int、C# string↔C/C++ char*),复杂结构体需用[StructLayout]指定内存布局。
函数名匹配:需对应 DLL 的导出函数名(C++ 要加extern "C"避免名字修饰,或用EntryPoint指定导出名)
调用约定匹配:必须和 C/C++ 函数的调用约定一致(如 Win32 API 默认StdCall,C/C++ 默认Cdecl),否则会栈溢出 / 程序崩溃
函数详解
static extern IntPtr GetActiveWindow();
返回值为IntPtr,为窗口句柄HWND,检索附加到调用线程消息队列中的活动窗口的句柄
static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
SetWindowPosFlags uFlags
);
hWnd : 要操作的窗口句柄
hWndInsertAfter : 控制窗口层级,最常用的是HWND_TOPMOST(置顶)和HWND_NOTOPMOST(取消置顶)

X/Y/cx/cy : 窗口坐标和尺寸,是否生效取决于uFlags
uFlags : 组合标志 , uFlags参数本身就是无符号整数(uint)

public static extern bool GetWindowRect(IntPtr hWnd, out RECT pos);
HWND : 窗口的句柄
pos : 指向 RECT 结构的指针,该结构接收窗口左上角和右下角的屏幕坐标
RECT结构体是 P/Invoke 中复杂类型封送的典型代表,也是 CLR 适配托管 / 非托管内存布局的核心场景(比如你调用 Windows API 控制窗口时,常会用RECT获取 / 设置窗口的矩形区域)
RECT是 Windows API 里的非托管结构体(C/C++ 定义),专门用来表示矩形区域(比如窗口的左上角 / 右下角坐标),原始定义:
// C/C++ 非托管RECT结构体(winuser.h)
typedef struct tagRECT {
LONG left; // 左边界(对应窗口X坐标)
LONG top; // 上边界(对应窗口Y坐标)
LONG right; // 右边界(左+宽度)
LONG bottom; // 下边界(上+高度)
} RECT, *LPRECT;
要让 CLR 正确适配,必须用[StructLayout]显式指定结构体的内存布局:
// C# 托管RECT结构体
[StructLayout(LayoutKind.Sequential)] // 核心:告诉CLR“按字段顺序排列内存”
public struct RECT
{
// 字段类型必须和非托管的LONG匹配(Windows的LONG是4字节整型,对应C#的int)
public int left;
public int top;
public int right;
public int bottom;
// 可选:封装便捷属性(比如计算窗口宽高),不影响CLR适配
public int Width => right - left;
public int Height => bottom - top;
}
LayoutKind.Sequential:强制 CLR按字段声明的顺序分配内存(和 C/C++ 的结构体默认布局一致); 如果不加[StructLayout]:CLR 可能为了性能优化 “重排字段顺序”(比如把 int 和 bool 放一起节省内存),导致内存布局和非托管 RECT 完全错位,调用 API 时会返回错误坐标甚至崩溃;
进阶:如果非托管结构体是 “按字节对齐”(比如#pragma pack(1)),需加Pack=1:[StructLayout(LayoutKind.Sequential, Pack=1)]。
只要内存结构对得上,CLR会完成匹配,这不同于C#自身的类型匹配
关于RECT:
评论(0)
暂无评论