3

So I've run into this unfortunate situation where I have to, as the title says, write a function declaration with an optional struct parameter.

Here is the struct:

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
  public int nLength;
  public IntPtr lpSecurityDescriptor;
  public int bInheritHandle;
}

Here is the function in the .dll advapi.dll:

LONG WINAPI RegSaveKey(
_In_     HKEY                  hKey,
_In_     LPCTSTR               lpFile,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

Here's my declaration so far:

[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegSaveKey(UInt32 hKey, string lpFile, [optional parameter here!!] );
River
  • 8,585
  • 14
  • 54
  • 67
Alvaromon
  • 190
  • 2
  • 16
  • Is this of use; https://stackoverflow.com/questions/2676128/default-arguments-for-structures ? – d219 Nov 30 '17 at 16:48
  • I think you need to declare the last argument with [Out, Optional] as shown here https://github.com/dotnet/roslyn/issues/13119 –  Nov 30 '17 at 16:50
  • 4
    Declare a class instead of a struct. Don't use `ref` in the pinvoke declaration. Now you can pass `null`. Alternatively, given that you rarely use this argument, just declare the argument as IntPtr and pass IntPtr.Zero. – Hans Passant Nov 30 '17 at 16:50

1 Answers1

1

For this, you should declare the 3rd argument as a IntPtr. When you want to pass it null, give it IntPtr.Zero. If you want to pass a real structure to it, Marshal the structure into memory - i.e. something like this

SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
// set anything you want in the sa structure here

IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)));
try {
    Marshal.StructureToPtr(sa, pnt, false)

    // call RegSaveKey here 
} finally {
    Marshal.FreeHGlobal(pnt);
}
River
  • 8,585
  • 14
  • 54
  • 67
MrMikeJJ
  • 114
  • 1
  • 4