You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:20:30