コード例 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AnsiStringMarshaller"/>.
        /// </summary>
        /// <param name="str">The string to marshal.</param>
        /// <param name="buffer">Buffer that may be used for marshalling.</param>
        /// <remarks>
        /// The <paramref name="buffer"/> must not be movable - that is, it should not be
        /// on the managed heap or it should be pinned.
        /// <seealso cref="CustomTypeMarshallerFeatures.CallerAllocatedBuffer"/>
        /// </remarks>
        public AnsiStringMarshaller(string?str, Span <byte> buffer)
        {
            _allocated = false;

            if (str is null)
            {
                _nativeValue = null;
                return;
            }

            // >= for null terminator
            if ((long)Marshal.SystemMaxDBCSCharSize * str.Length >= buffer.Length)
            {
                // Calculate accurate byte count when the provided stack-allocated buffer is not sufficient
                int exactByteCount = Marshal.GetAnsiStringByteCount(str); // Includes null terminator
                if (exactByteCount > buffer.Length)
                {
                    buffer     = new Span <byte>((byte *)Marshal.AllocCoTaskMem(exactByteCount), exactByteCount);
                    _allocated = true;
                }
            }

            _nativeValue = (byte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer));

            Marshal.GetAnsiStringBytes(str, buffer); // Includes null terminator
        }
コード例 #2
0
            /// <summary>
            /// Initialize the marshaller with a managed string and requested buffer.
            /// </summary>
            /// <param name="managed">The managed string</param>
            /// <param name="buffer">A request buffer of at least size, <see cref="BufferSize"/>.</param>
            public void FromManaged(string?managed, Span <byte> buffer)
            {
                _allocated = false;

                if (managed is null)
                {
                    _unmanagedValue = null;
                    return;
                }

                // >= for null terminator
                // Use the cast to long to avoid the checked operation
                if ((long)Marshal.SystemMaxDBCSCharSize * managed.Length >= buffer.Length)
                {
                    // Calculate accurate byte count when the provided stack-allocated buffer is not sufficient
                    int exactByteCount = Marshal.GetAnsiStringByteCount(managed); // Includes null terminator
                    if (exactByteCount > buffer.Length)
                    {
                        buffer     = new Span <byte>((byte *)NativeMemory.Alloc((nuint)exactByteCount), exactByteCount);
                        _allocated = true;
                    }
                }

                _unmanagedValue = (byte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer));

                Marshal.GetAnsiStringBytes(managed, buffer); // Includes null terminator
            }
コード例 #3
0
        /// <summary>
        /// Convert a string to an unmanaged version.
        /// </summary>
        /// <param name="managed">A managed string</param>
        /// <returns>An unmanaged string</returns>
        public static byte *ConvertToUnmanaged(string?managed)
        {
            if (managed is null)
            {
                return(null);
            }

            int         exactByteCount = Marshal.GetAnsiStringByteCount(managed); // Includes null terminator
            byte *      mem            = (byte *)Marshal.AllocCoTaskMem(exactByteCount);
            Span <byte> buffer         = new (mem, exactByteCount);

            Marshal.GetAnsiStringBytes(managed, buffer); // Includes null terminator
            return(mem);
        }
コード例 #4
0
        internal unsafe IntPtr MarshalToString(bool globalAlloc, bool unicode)
        {
            lock (_methodLock)
            {
                EnsureNotDisposed();

                UnprotectMemory();

                SafeBuffer?bufferToRelease = null;
                IntPtr     ptr             = IntPtr.Zero;
                int        byteLength      = 0;
                try
                {
                    Span <char> span = AcquireSpan(ref bufferToRelease).Slice(0, _decryptedLength);

                    if (unicode)
                    {
                        byteLength = (span.Length + 1) * sizeof(char);
                    }
                    else
                    {
                        byteLength = Marshal.GetAnsiStringByteCount(span);
                    }

                    if (globalAlloc)
                    {
                        ptr = Marshal.AllocHGlobal(byteLength);
                    }
                    else
                    {
                        ptr = Marshal.AllocCoTaskMem(byteLength);
                    }

                    if (unicode)
                    {
                        Span <char> resultSpan = new Span <char>((void *)ptr, byteLength / sizeof(char));
                        span.CopyTo(resultSpan);
                        resultSpan[resultSpan.Length - 1] = '\0';
                    }
                    else
                    {
                        Marshal.GetAnsiStringBytes(span, new Span <byte>((void *)ptr, byteLength));
                    }

                    IntPtr result = ptr;
                    ptr = IntPtr.Zero;
                    return(result);
                }
                finally
                {
                    // If we failed for any reason, free the new buffer
                    if (ptr != IntPtr.Zero)
                    {
                        new Span <byte>((void *)ptr, byteLength).Clear();

                        if (globalAlloc)
                        {
                            Marshal.FreeHGlobal(ptr);
                        }
                        else
                        {
                            Marshal.FreeCoTaskMem(ptr);
                        }
                    }

                    ProtectMemory();
                    bufferToRelease?.DangerousRelease();
                }
            }
        }