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.
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.
No C++ Struct member can have a null value.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With