Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add string marshallers for ANSI and platform-defined #288

Conversation

elinor-fung
Copy link
Member

@elinor-fung elinor-fung commented Nov 3, 2020

  • Update to latest test packages
    • Needed so that we reference a version of the framework assemblies that have OperatingSystem.IsWindows()
  • Add marshallers for handling CharSet.Ansi/UnmanagedType.LPStr and CharSet.Auto
    • They offload a bunch of the actual generation to the UTF-8 and UTF-16 marshallers and only partially participate in the conditional stackalloc logic.
  • Add tests

Ran on Windows and Linux (patched with the fix for component loading in muxer mode). Did not run on macOS.

cc @AaronRobinsonMSFT @jkoritzinsky

Ansi
public static partial string Method_Ansi(string p, in string pIn, ref string pRef, out string pOut)
{
    unsafe
    {
        pOut = default;
        string __retVal;
        //
        // Setup
        //
        byte *__retVal_gen_native;
        byte *__p_gen_native;
        bool p__allocated = false;
        byte *__pIn_gen_native;
        bool pIn__allocated = false;
        byte *__pRef_gen_native;
        byte *__pOut_gen_native;
        //
        // Marshal
        //
        if (System.OperatingSystem.IsWindows())
        {
            __p_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemAnsi(p);
        }
        else
        {
            if (p == null)
            {
                __p_gen_native = null;
            }
            else
            {
                int p__bytelen = (p.Length + 1) * 3 + 1;
                if (p__bytelen > 260)
                {
                    __p_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(p);
                    p__allocated = true;
                }
                else
                {
                    byte *p__stackptr = stackalloc byte[p__bytelen];
                    {
                        p__bytelen = System.Text.Encoding.UTF8.GetBytes(p, new System.Span<byte>(p__stackptr, p__bytelen));
                        p__stackptr[p__bytelen] = 0;
                    }

                    __p_gen_native = (byte *)p__stackptr;
                }
            }
        }

        if (System.OperatingSystem.IsWindows())
        {
            __pIn_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemAnsi(pIn);
        }
        else
        {
            if (pIn == null)
            {
                __pIn_gen_native = null;
            }
            else
            {
                int pIn__bytelen = (pIn.Length + 1) * 3 + 1;
                if (pIn__bytelen > 260)
                {
                    __pIn_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(pIn);
                    pIn__allocated = true;
                }
                else
                {
                    byte *pIn__stackptr = stackalloc byte[pIn__bytelen];
                    {
                        pIn__bytelen = System.Text.Encoding.UTF8.GetBytes(pIn, new System.Span<byte>(pIn__stackptr, pIn__bytelen));
                        pIn__stackptr[pIn__bytelen] = 0;
                    }

                    __pIn_gen_native = (byte *)pIn__stackptr;
                }
            }
        }

        if (System.OperatingSystem.IsWindows())
        {
            __pRef_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemAnsi(pRef);
        }
        else
        {
            __pRef_gen_native = null;
            if (pRef != null)
            {
                __pRef_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(pRef);
            }
        }

        //
        // Invoke
        //
        __retVal_gen_native = Method_Ansi__PInvoke__(__p_gen_native, &__pIn_gen_native, &__pRef_gen_native, &__pOut_gen_native);
        //
        // Unmarshal
        //
        if (System.OperatingSystem.IsWindows())
        {
            __retVal = __retVal_gen_native == null ? null : new string ((sbyte *)__retVal_gen_native);
        }
        else
        {
            __retVal = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__retVal_gen_native);
        }

        if (System.OperatingSystem.IsWindows())
        {
            pRef = __pRef_gen_native == null ? null : new string ((sbyte *)__pRef_gen_native);
        }
        else
        {
            pRef = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__pRef_gen_native);
        }

        if (System.OperatingSystem.IsWindows())
        {
            pOut = __pOut_gen_native == null ? null : new string ((sbyte *)__pOut_gen_native);
        }
        else
        {
            pOut = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__pOut_gen_native);
        }

        //
        // Cleanup
        //
        if (p__allocated)
        {
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__p_gen_native);
        }

        if (pIn__allocated)
        {
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pIn_gen_native);
        }

        System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pRef_gen_native);
        System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pOut_gen_native);
        return __retVal;
    }
}

[System.Runtime.InteropServices.DllImportAttribute("DoesNotExist", CharSet = System.Runtime.InteropServices.CharSet.Ansi, EntryPoint = "Method_Ansi")]
extern private static unsafe byte *Method_Ansi__PInvoke__(byte *p, byte **pIn, byte **pRef, byte **pOut);
Auto
public static partial string Method_Auto(string p, in string pIn, ref string pRef, out string pOut)
{
    unsafe
    {
        pOut = default;
        string __retVal;
        //
        // Setup
        //
        void *__retVal_gen_native = null;
        void *__p_gen_native = null;
        bool p__allocated = false;
        void *__pIn_gen_native = null;
        bool pIn__allocated = false;
        void *__pRef_gen_native = null;
        void *__pOut_gen_native = null;
        //
        // Marshal
        //
        if (!System.OperatingSystem.IsWindows())
        {
            if (p == null)
            {
                __p_gen_native = null;
            }
            else
            {
                int p__bytelen = (p.Length + 1) * 3 + 1;
                if (p__bytelen > 260)
                {
                    __p_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(p);
                    p__allocated = true;
                }
                else
                {
                    byte *p__stackptr = stackalloc byte[p__bytelen];
                    {
                        p__bytelen = System.Text.Encoding.UTF8.GetBytes(p, new System.Span<byte>(p__stackptr, p__bytelen));
                        p__stackptr[p__bytelen] = 0;
                    }

                    __p_gen_native = (byte *)p__stackptr;
                }
            }
        }

        if (System.OperatingSystem.IsWindows())
        {
            if (pIn == null)
            {
                __pIn_gen_native = null;
            }
            else
            {
                int pIn__bytelen = (pIn.Length + 1) * 2;
                if (pIn__bytelen > 520)
                {
                    __pIn_gen_native = (ushort *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(pIn);
                    pIn__allocated = true;
                }
                else
                {
                    byte *pIn__stackptr = stackalloc byte[pIn__bytelen];
                    ((System.ReadOnlySpan<char>)pIn).CopyTo(new System.Span<char>(pIn__stackptr, pIn__bytelen));
                    __pIn_gen_native = (ushort *)pIn__stackptr;
                }
            }
        }
        else
        {
            if (pIn == null)
            {
                __pIn_gen_native = null;
            }
            else
            {
                int pIn__bytelen = (pIn.Length + 1) * 3 + 1;
                if (pIn__bytelen > 260)
                {
                    __pIn_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(pIn);
                    pIn__allocated = true;
                }
                else
                {
                    byte *pIn__stackptr = stackalloc byte[pIn__bytelen];
                    {
                        pIn__bytelen = System.Text.Encoding.UTF8.GetBytes(pIn, new System.Span<byte>(pIn__stackptr, pIn__bytelen));
                        pIn__stackptr[pIn__bytelen] = 0;
                    }

                    __pIn_gen_native = (byte *)pIn__stackptr;
                }
            }
        }

        if (System.OperatingSystem.IsWindows())
        {
            __pRef_gen_native = null;
            if (pRef != null)
            {
                __pRef_gen_native = (ushort *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(pRef);
            }
        }
        else
        {
            __pRef_gen_native = null;
            if (pRef != null)
            {
                __pRef_gen_native = (byte *)System.Runtime.InteropServices.Marshal.StringToCoTaskMemUTF8(pRef);
            }
        }

        //
        // Invoke
        //
        fixed (char *__p_gen_native__pinned = p)
        {
            __retVal_gen_native = Method_Auto__PInvoke__(System.OperatingSystem.IsWindows() ? (ushort *)__p_gen_native__pinned : __p_gen_native, &__pIn_gen_native, &__pRef_gen_native, &__pOut_gen_native);
        }

        //
        // Unmarshal
        //
        if (System.OperatingSystem.IsWindows())
        {
            __retVal = __retVal_gen_native == null ? null : new string ((char *)__retVal_gen_native);
        }
        else
        {
            __retVal = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__retVal_gen_native);
        }

        if (System.OperatingSystem.IsWindows())
        {
            pRef = __pRef_gen_native == null ? null : new string ((char *)__pRef_gen_native);
        }
        else
        {
            pRef = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__pRef_gen_native);
        }

        if (System.OperatingSystem.IsWindows())
        {
            pOut = __pOut_gen_native == null ? null : new string ((char *)__pOut_gen_native);
        }
        else
        {
            pOut = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((System.IntPtr)__pOut_gen_native);
        }

        //
        // Cleanup
        //
        if (p__allocated)
        {
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__p_gen_native);
        }

        if (pIn__allocated)
        {
            System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pIn_gen_native);
        }

        System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pRef_gen_native);
        System.Runtime.InteropServices.Marshal.FreeCoTaskMem((System.IntPtr)__pOut_gen_native);
        return __retVal;
    }
}

[System.Runtime.InteropServices.DllImportAttribute("DoesNotExist", CharSet = System.Runtime.InteropServices.CharSet.Auto, EntryPoint = "Method_Auto")]
extern private static unsafe void *Method_Auto__PInvoke__(void *p, void **pIn, void **pRef, void **pOut);

@elinor-fung elinor-fung added the area-DllImportGenerator Source Generated stubs for P/Invokes in C# label Nov 3, 2020
@elinor-fung elinor-fung changed the title String marshaller ansi auto Add string marshallers for ANSI and platform-defined Nov 3, 2020
Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@elinor-fung elinor-fung merged commit ebbd0b2 into dotnet:feature/DllImportGenerator Nov 5, 2020
@elinor-fung elinor-fung deleted the stringMarshaller-ansi-auto branch November 5, 2020 00:03
jkoritzinsky pushed a commit to jkoritzinsky/runtime that referenced this pull request Sep 20, 2021
…ab#288)

* Update to latest version of analyzer test package
* Add string marshaller for CharSet.Ansi
* Add string marshaller for CharSet.Auto
* Update compatibility doc

Commit migrated from dotnet/runtimelab@ebbd0b2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-DllImportGenerator Source Generated stubs for P/Invokes in C#
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants