microsoft / CsWin32

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.
MIT License
1.99k stars 84 forks source link

GetCurrentProcessToken results in DllImport for "FORCEINLINE" #1097

Closed jlaanstra closed 6 months ago

jlaanstra commented 6 months ago

Actual behavior

Adding GetCurrentProcessToken to nativemethods.txt results in the following DllImport:

[DllImport("FORCEINLINE", ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern winmdroot.Foundation.HANDLE GetCurrentProcessToken();

Expected behavior

The correct DllImport with the actual dll name.

Repro steps

  1. NativeMethods.txt content:

    GetCurrentProcessToken
  2. NativeMethods.json content (if present):

    {
    "$schema": "https://aka.ms/CsWin32.schema.json",
    "emitSingleFile": false,
    "allowMarshaling": false
    }
  3. Any of your own code that should be shared?

Context

jlaanstra commented 6 months ago

Some further digging shows that this isn't even defined in a dll, so maybe cswin32 should generate a dllimport like this?

matthew-a-thomas commented 6 months ago

Same thing happens with GetCurrentThreadToken:

// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------

#pragma warning disable CS1591,CS1573,CS0465,CS0649,CS8019,CS1570,CS1584,CS1658,CS0436,CS8981
using global::System;
using global::System.Diagnostics;
using global::System.Diagnostics.CodeAnalysis;
using global::System.Runtime.CompilerServices;
using global::System.Runtime.InteropServices;
using global::System.Runtime.Versioning;
using winmdroot = global::Windows.Win32;
namespace Windows.Win32
{

    /// <content>
    /// Contains extern methods from "FORCEINLINE".
    /// </content>
    internal static partial class PInvoke
    {
        /// <inheritdoc cref="GetCurrentThreadToken()"/>
        internal static unsafe Microsoft.Win32.SafeHandles.SafeFileHandle GetCurrentThreadToken_SafeHandle()
        {
            winmdroot.Foundation.HANDLE __result = PInvoke.GetCurrentThreadToken();
            return new Microsoft.Win32.SafeHandles.SafeFileHandle(__result, ownsHandle: false);
        }

        /// <summary>Retrieves a pseudo-handle that you can use as a shorthand way to refer to the impersonation token that was assigned to the current thread.</summary>
        /// <returns>A pseudo-handle that you can use as a shorthand way to refer to the <a href="https://docs.microsoft.com/windows/desktop/SecGloss/i-gly">impersonation token</a> that was assigned to the current thread.</returns>
        /// <remarks>
        /// <para>A pseudo-handle is a special constant that can function as the impersonation token for the current thread.  The calling thread can use a pseudo-handle to specify the impersonation token for that thread whenever a token handle is required.  Child processes do not inherit pseudo-handles. Starting in Windows 8, this pseudo-handle has only TOKEN_QUERY and TOKEN_QUERY_SOURCE access rights. The pseudo-handle cannot be duplicated by the <a href="https://docs.microsoft.com/windows/desktop/api/handleapi/nf-handleapi-duplicatehandle">DuplicateHandle</a> function or the <a href="https://docs.microsoft.com/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetoken">DuplicateToken</a> function. You do not need to close the pseudo-handle when you no longer need it. If you call the <a href="https://docs.microsoft.com/windows/desktop/api/handleapi/nf-handleapi-closehandle">CloseHandle</a> function with a pseudo-handle, the function has no effect.</para>
        /// <para><see href="https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadtoken#">Read more on docs.microsoft.com</see>.</para>
        /// </remarks>
        [DllImport("FORCEINLINE", ExactSpelling = true)]
        [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
        internal static extern winmdroot.Foundation.HANDLE GetCurrentThreadToken();
    }
}
matthew-a-thomas commented 6 months ago

Seems to come from this commit? https://github.com/microsoft/win32metadata/commit/87920a2ac1026a2013ca3e721793b077e892b0a7

matthew-a-thomas commented 6 months ago

There's some discussion about the [DllImport] in this thread: https://github.com/microsoft/win32metadata/issues/436

Sounds like consumers of the metadata (e.g. cswin32) are supposed to filter that out or something? I dunno. In the meantime I'm just going to use the relevant constant:

Name Value
GetCurrentProcessToken -4
GetCurrentThreadToken -5
GetCurrentThreadEffectiveToken -6
using System;
using Windows.Win32.Foundation;

static class PInvokeWorkarounds
{
    /// <summary>
    /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocesstoken
    /// </summary>
    public static HANDLE GetCurrentProcessToken() => new((IntPtr)(-4));

    /// <summary>
    /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadtoken
    /// </summary>
    public static HANDLE GetCurrentThreadToken() => new((IntPtr)(-5));

    /// <summary>
    /// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadeffectivetoken
    /// </summary>
    public static HANDLE GetCurrentThreadEffectiveToken() => new((IntPtr)(-6));
}
matthew-a-thomas commented 6 months ago

Oh would you look at that. This bug report is essentially a duplicate of https://github.com/microsoft/CsWin32/issues/897