1

I am trying to PInvoke CreateDesktop in a way that passes the flag to inherit the desktop by child processes. The declaration is as follows:

[DllImport("user32", EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags,
                                                  int dwDesiredAccess, [MarshalAs(UnmanagedType.LPStruct)] SECURITY_ATTRIBUTES lpsa);

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

And I use it as follows:

Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
            sa.nLength = Marshal.SizeOf(sa);
            sa.bInheritHandle = 1;
            testDesktopHandle = Win32.CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, Win32.GENERIC_ALL, sa);

And it unfortunately doesn't work, I get the following error:

System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'parameter #6': Invalid managed/unmanaged type combination (this value type must be paired with Struct).

Any ideas what I am doing wrong?

Grzenio
  • 35,875
  • 47
  • 158
  • 240
  • it is always worth checking http://www.pinvoke.net/ for these type of problems. – Ian Ringrose Sep 21 '09 at 14:17
  • 1
    Unless the reason you're here is because you got this exception from using a declaration you got from pinvoke.net... *(raises hand)* – Daniel Earwicker Sep 12 '14 at 09:52
  • @IanRingrose pinvoke.net declaration of `CreateDesktop` function is still bugged. It works only if one uses class to declare `SECURITY_ATTRIBUTES` and passes `null` as it's value. – Lightman Jun 05 '17 at 11:45

2 Answers2

5

Try changing parameter #6 to

static extern IntPtr CreateDesktop(..., [In] ref SECURITY_ATTRIBUTES lpsa);

(This compiles and doesn't throw an exception at runtime, but I've tested it only with bogus arguments.)

Compare with C++ declaration of CreateDesktop:

HDESK WINAPI CreateDesktop(..., __in_opt LPSECURITY_ATTRIBUTES lpsa);
                                  ↑      ↑ ↑
                                  [In] ref SECURITY_ATTRIBUTES lpsa

LP stands for "long pointer", i.e. LPSECURITY_ATTRIBUTES is a pointer to a SECURITY_ATTRIBUTES struct. So in C# you need to pass your struct instance (value type) by reference.

dtb
  • 213,145
  • 36
  • 401
  • 431
1

Consider using the following prototype instead:

    [DllImport("user32", EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags,
                                              int dwDesiredAccess, IntPtr lpsa);

Then to call it just create a pinned handle:

        GCHandle handle = GCHandle.Alloc(myStruct);
        try {
            IntPtr pinnedAddress = handle.AddrOfPinnedObject();
        }
        finally {
            handle.Free();
        }

This works VERY well for calling PInvoke'd methods with structs.

csharptest.net
  • 62,602
  • 11
  • 71
  • 89