如何为pinvoke调用的结构分配空值?

时间:2013-06-04 07:00:54

标签: c# struct pinvoke marshalling

我想调用LsaOpenPolicy,它采用LSA_OBJECT_ATTRIBUTES结构。我正在使用the struct definition from pinvoke.net。此结构具有字段public LSA_UNICODE_STRING ObjectName;

LSA_OBJECT_ATTRIBUTES MSDN文章说:

  

当您致电LsaOpenPolicy时,请将此结构的成员初始化为 NULL 或零,因为该功能不使用该信息。

具体而言:

  

的ObjectName

     

应该是 NULL

虽然我可以将LSA_OBJECT_ATTRIBUTES结构体的其他字段分配给IntPtr.Zero(或仅仅为0指定值类型),但我无法看到ObjectName结构的其他字段1}}。具体地,

  

无法将类型'System.IntPtr'隐式转换为'LSA_UNICODE_STRING'

在这种情况下我该怎么办?我应该只初始化长度为零的LSA_UNICODE_STRING(长度为0,最大长度为0,空/空缓冲区)?我应该更改LSA_OBJECT_ATTRIBUTES定义,以便该字段是IntPtr吗?我应该让它可以为空并将null分配给该字段吗?

我对内存管理的经验很少,所以我对任何可能导致内存泄漏的事情都很谨慎。

1 个答案:

答案 0 :(得分:3)

LSA_UNICODE_STRING声明为class而不是struct。通过这样做,您可以将其作为引用类型。这符合LSA_OBJECT_ATTRIBUTES的声明,因为ObjectName具有类型PLSA_UNICODE_STRING,它是指向结构的指针。执行此操作时,您需要指定LayoutKind.Sequential,因为这不是类的默认值。完成此更改后,您可以将变量设置为null

[StructLayout(LayoutKind.Sequential)]
class PLSA_UNICODE_STRING 
{
    public UInt16 Length;
    public UInt16 MaximumLength;
    public IntPtr Buffer;
}

您可以对LSA_OBJECT_ATTRIBUTES采用相同的政策,以便将其作为null传递。

[StructLayout(LayoutKind.Sequential)]
class PLSA_OBJECT_ATTRIBUTES
{
   public uint Length;
   public IntPtr RootDirectory;
   public PLSA_UNICODE_STRING ObjectName;
   public uint Attributes;
   public IntPtr SecurityDescriptor;
   public IntPtr SecurityQualityOfService;
}

[DllImport("advapi32.dll")]
static extern uint LsaOpenPolicy(
    PLSA_UNICODE_STRING SystemName,
    PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
    uint DesiredAccess,
    out IntPtr PolicyHandle
);

请注意,pinvoke.net上的声明错误地使用了SetLastError=true上的LsaOpenPolicy。这是错误的,因为错误代码返回到返回值。我还删除了PreserveSigtrue的设置,因为这是默认设置。它们的LSA_OBJECT_ATTRIBUTES声明也显示错误,因为ObjectName参数的类型LSA_UNICODE_STRING是结构而不是指向它的指针。

我建议你对pinvoke.net上发现的内容持极端怀疑态度。该网站上的很大一部分声明都是不正确的。

您询问使用可空类型的可能性。根据@ JaredPar的answer here,这不是一个选择。