/// <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 }
/// <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 }
/// <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); }
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(); } } }