LibraryImport:源生成的 P/Invoke 不支持类型“*”

问题描述 投票:0回答:1

我正在将 this 实现(以桌面用户身份启动进程)从

[DllImport]
移植到
[LibraryImport]
(.NET 8)。 Visual Studio Roslyn 已将方法“AdjustTokenPrivileges”更改为

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

我收到此错误:

SYSLIB1051: The type 'MyMethods.TOKEN_PRIVILEGES' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'newst'.

下一个方法'CreateProcessWithTokenW'更改为

[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, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);

错误所在:

SYSLIB1051: The type 'MyMethods.STARTUPINFO' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'lpStartupInfo'.

我尝试将 Int32 更改为 int,将 UInt32 更改为 uint,并将字符串更改为不安全的 char*,如建议的here。我也尝试实现CaiB的答案,但我无法完成它。

c# process pinvoke
1个回答
0
投票

好吧,我不知道p/invoke的新一代酸味是什么疯狂的想法,但这远非简单。它比前一个功能强大得多,可以让您进行微调,但有些明显且简单的事情是它无法单独完成的,而且它通常不是 100% 兼容,必须做一些工作。您可以添加远未完成的文档。

好吧,所以就有了 blittable types 的概念(无论哪段代码访问它,在二进制级别上都是相同的类型)。这根本不是什么新鲜事,但它的 blittable 列表似乎受到了限制。显然,大小恒定的 blittable 类型数组本身不被视为可 blittable...

因此,当类型不可 blittable 时,您必须自己封送类型,如下所述:https://github.com/dotnet/runtime/issues/75376

这是新系统的一个已知缺陷。我们没有 今天的源生成器用于生成编组信息 用户定义的类型。您需要使用手动定义编组器 如果您想使用新的自定义类型编组器模型 使用 LibraryImport 的非 blittable 用户定义类型。

废话已经够多了,这里是 TOKEN_PRIVILEGES 编组器的示例:

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

    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
    public LUID_AND_ATTRIBUTES[] Privileges;
}

一些有用的文档:用于源生成的互操作的用户定义类型编组教程:在源生成的 P/Invoke 中使用自定义编组器

你可以这样称呼它:

[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);

第二个,只要去掉

[In]
,由于某些原因,发电机就卡住了:

[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);

我在这里放置了完整的源代码副本:https://gist.github.com/smourier/70cc9208b47534ba475279a4554180ce

© www.soinside.com 2019 - 2024. All rights reserved.