See the question and my original answer on StackOverflow

The new soure generation for p/invoke is far from being simple. It's much more powerful than the previous one and let you finely tune things, but there are obvious and simple things that it cannot do alone, and it's generally not 100% compatible, some work has to be done. You can add to that the far-from-being-complete documentation.

Ok, so there's the concept of blittable types (a type that is the same at binary level, whatever piece of code, managed or unmanaged, accesses it). It's not new at all but it seems the list of what's blittable has been restricted. Apparently, an array of blittable types, of constant size is not considered as blittable itself anymore.

So, when a type is not blittable, you must marshal the type by yourself, as stated here: https://github.com/dotnet/runtime/issues/75376

This is a known deficiency in the new system. We do not have a source-generator today for generating marshalling information for a user-defined type. You'll need to manually define a marshaller using the new custom type marshaller model if you want to use a non-blittable user-defined type with LibraryImport.

Here is a sample for a marshaller for TOKEN_PRIVILEGES:

[CustomMarshaller(typeof(TOKEN_PRIVILEGES), MarshalMode.ManagedToUnmanagedIn, typeof(TOKEN_PRIVILEGESMarshaller))]
private unsafe static class TOKEN_PRIVILEGESMarshaller
{
    public ref struct Unmanaged
    {
        public uint PrivilegeCount;
        public LUID_AND_ATTRIBUTES* Privileges;
    }

    // note: you can put a breakpoint here and walk the stack
    // back, you will see the inner workings of the generated source
    public static Unmanaged ConvertToUnmanaged(TOKEN_PRIVILEGES managed)
    {
        var unmanaged = new Unmanaged
        {
            PrivilegeCount = managed.PrivilegeCount,
            Privileges = ArrayMarshaller<LUID_AND_ATTRIBUTES, LUID_AND_ATTRIBUTES>.AllocateContainerForUnmanagedElements(managed.Privileges, out var count)
        };
        ArrayMarshaller<LUID_AND_ATTRIBUTES, LUID_AND_ATTRIBUTES>.GetManagedValuesSource(managed.Privileges)
            .CopyTo(ArrayMarshaller<LUID_AND_ATTRIBUTES, LUID_AND_ATTRIBUTES>
            .GetUnmanagedValuesDestination(unmanaged.Privileges, count));
        return unmanaged;
    }

    public static void Free(Unmanaged unmanaged) => ArrayMarshaller<LUID_AND_ATTRIBUTES, LUID_AND_ATTRIBUTES>.Free(unmanaged.Privileges);
}

[NativeMarshalling(typeof(TOKEN_PRIVILEGESMarshaller))]
private struct TOKEN_PRIVILEGES
{
    public uint PrivilegeCount;
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // you can keep that for compat reasons if you share the source with older .NET projects
    public LUID_AND_ATTRIBUTES[] Privileges;
}

Some useful documentation: User Defined Type Marshalling for Source-Generated Interop and Tutorial: Use custom marshallers in source-generated P/Invokes

And you can call it like that:

[LibraryImport("advapi32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool AdjustTokenPrivileges(IntPtr htok, [MarshalAs(UnmanagedType.Bool)] bool disall, TOKEN_PRIVILEGES newst, int len, IntPtr prev, IntPtr relen);

For the second one, just remove [In], for some reasons, the generator chokes on it:

[LibraryImport("advapi32", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool CreateProcessWithTokenW(IntPtr hToken, int dwLogonFlags, string lpApplicationName, string lpCommandLine, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

I've put a full source copy here: https://gist.github.com/smourier/70cc9208b47534ba475279a4554180ce

Now, it's interesting to look at the generated code:

enter image description here

As you can see, in the end, it's just calling the method using the DllImport way with the unmanaged struct. So in this case, I don't think it's useful to use LibraryImport at all.

PS: in this very special case, since it's an array of 1 element, you could just declare this:

    private struct TOKEN_PRIVILEGES
    {
        public uint PrivilegeCount;
        public LUID_AND_ATTRIBUTES Privileges;
    }