Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I assign a null value to a struct for a pinvoke call? [duplicate]

I would like to call LsaOpenPolicy, which takes a LSA_OBJECT_ATTRIBUTES struct. I am using the struct definition from pinvoke.net. This struct has the field public LSA_UNICODE_STRING ObjectName;.

The LSA_OBJECT_ATTRIBUTES MSDN article says:

When you call LsaOpenPolicy, initialize the members of this structure to NULL or zero because the function does not use the information.

And specifically:

ObjectName

    Should be NULL.

While I can assign the other fields of the LSA_OBJECT_ATTRIBUTES struct to IntPtr.Zero (or just plain 0 for the value types), I cannot see a way to do so for ObjectName. Specifically,

Cannot implicitly convert type 'System.IntPtr' to 'LSA_UNICODE_STRING'

What should I do in this case? Should I just initialise a LSA_UNICODE_STRING of length zero (length 0, maximumlength 0, empty/null buffer)? Should I change the LSA_OBJECT_ATTRIBUTES definition so that field is an IntPtr? Should I make it nullable and assign null to that field?

I have very little experience with memory management, so I am rather wary of anything that could cause memory leaks.

like image 279
Bob Avatar asked Jun 04 '13 07:06

Bob


People also ask

Can we a assign null to struct variable?

You can't assign null to an element of the list because structs are value types, while null means an empty pointer, and so can only be assigned to reference type variables.

Can a struct be null C++?

No C++ Struct member can have a null value.

Can a ref be null?

A reference may be null. The variable may only be dereferenced when the compiler can guarantee that the value isn't null . These variables may be initialized with the default null value and may be assigned the value null in other code.


1 Answers

Declare LSA_UNICODE_STRING to be a class rather than a struct. By doing so you make it a reference type. That matches the declaration of LSA_OBJECT_ATTRIBUTES because ObjectName has type PLSA_UNICODE_STRING which is a pointer to the struct. You do need to specify LayoutKind.Sequential when you do this since that's not the default for a class. Once you've made this change, you can set the variable to null.

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

You can adopt the same policy for LSA_OBJECT_ATTRIBUTES to allow that to be passed as 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
);

Note that the declaration on pinvoke.net erroneously uses SetLastError=true on LsaOpenPolicy. That's wrong because the error code comes back in the return value. I also removed the setting of PreserveSig to true since that is the default. Their declaration of LSA_OBJECT_ATTRIBUTES also appears wrong since the ObjectName parameter has type LSA_UNICODE_STRING which is the struct rather than a pointer to it.

I would advise you to treat what you find on pinvoke.net with extreme scepticism. A large proportion of the declarations on that site are simply incorrect.

You ask about the possibility of using nullable types. According to @JaredPar's answer here, that's not an option.

like image 199
David Heffernan Avatar answered Oct 13 '22 19:10

David Heffernan