在.NET中调用GetEffectiveRightsFromAclW:C的_TRUSTEE_W转C#结构体
Win32 TRUSTEE_W结构体解析与.NET转换方案
一、你的三个疑问解答
1. C语言union的理解是否正确?
完全正确。C语言的union是共用体,所有成员共享同一块内存空间,同一时刻只能使用其中一个成员,结构体中union的内存大小等于其内部最大成员的尺寸。
2. ptstrName重复出现的含义
这是Win32 API为兼容旧代码设计的写法:
- 早期版本的
TRUSTEE_W结构体只有末尾的LPWCH ptstrName字段,仅支持通过名称指定受托人; - 后续扩展功能时,加入了匿名
union以支持SID、对象+SID等多种受托人标识方式,但为了兼容依赖旧字段的代码,保留了末尾的ptstrName; - 实际上,匿名
union内的ptstrName和结构体末尾的ptstrName指向同一块内存——匿名union没有名称,其成员直接成为结构体的成员,重名后编译器会将它们视为同一个字段; - 另外,
LPWSTR和LPWCH本质等价,都是指向宽字符的指针,只是命名习惯不同(前者侧重“字符串”,后者侧重“字符”)。
3. typedef最后一行的含义
这是C语言一次性定义多个类型别名的语法:
TRUSTEE_W:结构体_TRUSTEE_W的标准别名;*PTRUSTEE_W:指向TRUSTEE_W的指针类型别名;TRUSTEEW:TRUSTEE_W的缩写形式(Win32 API常见的简化命名方式);*PTRUSTEEW:指向TRUSTEEW的指针类型别名;
本质是给结构体本身和它的指针各起了两个名字,方便不同场景下的代码编写。
二、正确的C#结构体转换方案
你的尝试存在两个核心问题:一是直接用string会触发.NET自动封送,不符合Win32原始指针的处理逻辑;二是错误地重复声明了同一块内存的字段。以下是适配x64/x86架构的正确实现:
1. 先定义依赖的枚举类型
using System.Runtime.InteropServices; public enum MULTIPLE_TRUSTEE_OPERATION : int { NO_MULTIPLE_TRUSTEE = 0, TRUSTEE_IS_IMPERSONATE = 1 } public enum TRUSTEE_FORM : int { TRUSTEE_IS_SID = 0, TRUSTEE_IS_NAME = 1, TRUSTEE_BAD_FORM = 2, TRUSTEE_IS_OBJECTS_AND_SID = 3, TRUSTEE_IS_OBJECTS_AND_NAME = 4 } public enum TRUSTEE_TYPE : int { TRUSTEE_IS_UNKNOWN = 0, TRUSTEE_IS_USER = 1, TRUSTEE_IS_GROUP = 2, TRUSTEE_IS_DOMAIN = 3, TRUSTEE_IS_ALIAS = 4, TRUSTEE_IS_WELL_KNOWN_GROUP = 5, TRUSTEE_IS_DELETED = 6, TRUSTEE_IS_INVALID = 7, TRUSTEE_IS_COMPUTER = 8 }
2. 核心TRUSTEE_W结构体
[StructLayout(LayoutKind.Explicit, Size = 40)] // x64下对齐后总大小40字节,x86下可改为Size=24 public struct TRUSTEE_W { [FieldOffset(0)] public IntPtr pMultipleTrustee; [FieldOffset(8)] public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation; [FieldOffset(12)] public TRUSTEE_FORM TrusteeForm; [FieldOffset(16)] public TRUSTEE_TYPE TrusteeType; // 匿名union的所有成员共用同一内存偏移 [FieldOffset(20)] public IntPtr ptstrName; // 兼容旧字段,对应TRUSTEE_IS_NAME场景 [FieldOffset(20)] public IntPtr pSid; // 对应TRUSTEE_IS_SID场景 [FieldOffset(20)] public IntPtr pObjectsAndSid; // 对应TRUSTEE_IS_OBJECTS_AND_SID场景 [FieldOffset(20)] public IntPtr pObjectsAndName; // 对应TRUSTEE_IS_OBJECTS_AND_NAME场景 }
3. GetEffectiveRightsFromAclW函数声明
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern uint GetEffectiveRightsFromAclW( IntPtr pAcl, ref TRUSTEE_W pTrustee, out uint pEffectiveRights );
使用示例
// 示例:通过用户名获取有效权限 var trustee = new TRUSTEE_W { TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME, TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER, ptstrName = Marshal.StringToHGlobalUni("DOMAIN\\Username") }; uint effectiveRights; uint result = GetEffectiveRightsFromAclW(aclPtr, ref trustee, out effectiveRights); // 使用后释放内存 Marshal.FreeHGlobal(trustee.ptstrName);
内容的提问来源于stack exchange,提问作者Mike Bruno
相关产品推荐
相关产品推荐

