internal static unsafe IntPtr ConvertToNative(int flags, string strManaged) { if (null == strManaged) { return(IntPtr.Zero); } byte[]? bytes = null; int nb = 0; if (strManaged.Length > 0) { bytes = AnsiCharMarshaler.DoAnsiConversion(strManaged, 0 != (flags & 0xFF), 0 != (flags >> 8), out nb); } uint length = (uint)nb; IntPtr bstr = Marshal.AllocBSTRByteLen(length); if (bytes != null) { Buffer.Memmove(ref *(byte *)bstr, ref MemoryMarshal.GetArrayDataReference(bytes), length); } return(bstr); }
internal static unsafe IntPtr ConvertToNative(string strManaged, IntPtr pNativeBuffer) { if (null == strManaged) { return(IntPtr.Zero); } else { bool hasTrailByte = strManaged.TryGetTrailByte(out byte trailByte); uint lengthInBytes = (uint)strManaged.Length * 2; if (hasTrailByte) { // this is an odd-sized string with a trailing byte stored in its sync block lengthInBytes++; } byte *ptrToFirstChar; if (pNativeBuffer != IntPtr.Zero) { // If caller provided a buffer, construct the BSTR manually. The size // of the buffer must be at least (lengthInBytes + 6) bytes. #if DEBUG uint length = *((uint *)pNativeBuffer); Debug.Assert(length >= lengthInBytes + 6, "BSTR localloc'ed buffer is too small"); #endif // set length *((uint *)pNativeBuffer) = lengthInBytes; ptrToFirstChar = (byte *)pNativeBuffer + 4; } else { // If not provided, allocate the buffer using Marshal.AllocBSTRByteLen so // that odd-sized strings will be handled as well. ptrToFirstChar = (byte *)Marshal.AllocBSTRByteLen(lengthInBytes); } // copy characters from the managed string Buffer.Memmove(ref *(char *)ptrToFirstChar, ref strManaged.GetRawStringData(), (nuint)strManaged.Length + 1); // copy the trail byte if present if (hasTrailByte) { ptrToFirstChar[lengthInBytes - 1] = trailByte; } // return ptr to first character return((IntPtr)ptrToFirstChar); } }
internal static unsafe byte *StringToAnsiBstrBuffer(string s) { if (s is null) { return((byte *)IntPtr.Zero); } int stringLength = s.Length; fixed(char *pStr = s) { int nativeLength = PInvokeMarshal.GetByteCount(pStr, stringLength); byte *bstr = (byte *)Marshal.AllocBSTRByteLen((uint)nativeLength); PInvokeMarshal.ConvertWideCharToMultiByte(pStr, stringLength, bstr, nativeLength, bestFit: false, throwOnUnmappableChar: false); return(bstr); } }
/// <summary> /// Initializes the marshaller with a managed string and requested buffer. /// </summary> /// <param name="managed">The managed string to initialize the marshaller with.</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) { _ptrToFirstChar = null; return; } ushort *ptrToFirstChar; int lengthInBytes = checked (sizeof(char) * managed.Length); // A caller provided buffer must be at least (lengthInBytes + 6) bytes // in order to be constructed manually. The 6 extra bytes are 4 for byte length and 2 for wide null. int manualBstrNeeds = checked (lengthInBytes + 6); if (manualBstrNeeds > buffer.Length) { // Use precise byte count when the provided stack-allocated buffer is not sufficient ptrToFirstChar = (ushort *)Marshal.AllocBSTRByteLen((uint)lengthInBytes); _allocated = true; } else { // Set length and update buffer target byte *pBuffer = (byte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); *((uint *)pBuffer) = (uint)lengthInBytes; ptrToFirstChar = (ushort *)(pBuffer + sizeof(uint)); } // Confirm the size is properly set for the allocated BSTR. Debug.Assert(lengthInBytes == Marshal.SysStringByteLen((IntPtr)ptrToFirstChar)); // Copy characters from the managed string managed.CopyTo(new Span <char>(ptrToFirstChar, managed.Length)); ptrToFirstChar[managed.Length] = '\0'; // null-terminate _ptrToFirstChar = ptrToFirstChar; }