diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs index 0e38a100098b7a..518b9c8cf1f296 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs @@ -1654,7 +1654,9 @@ class UTF8StringMarshaller : Marshaller private ILLocalVariable? _marshallerInstance = null; - private TypeDesc Marshaller => Context.SystemModule.GetKnownType("System.Runtime.InteropServices.Marshalling", "Utf8StringMarshaller"); + private MetadataType Marshaller => Context.SystemModule.GetKnownType("System.Runtime.InteropServices.Marshalling", "Utf8StringMarshaller"); + + private MetadataType MarshallerIn => Marshaller.GetNestedType("ManagedToUnmanagedIn"); internal override bool CleanupRequired => true; @@ -1663,24 +1665,27 @@ internal override void EmitElementCleanup(ILCodeStream codeStream, ILEmitter emi Debug.Assert(_marshallerInstance is null); codeStream.Emit(ILOpcode.call, emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); + Marshaller.GetKnownMethod("Free", null))); } protected override void TransformManagedToNative(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; - TypeDesc marshaller = Marshaller; - - if (_marshallerInstance == null) - _marshallerInstance = emitter.NewLocal(marshaller); if (In && !Out && !IsManagedByRef) { + TypeDesc marshallerIn = MarshallerIn; + + if (_marshallerInstance == null) + _marshallerInstance = emitter.NewLocal(marshallerIn); + var vBuffer = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.IntPtr)); codeStream.EmitLdc(LocalBufferLength); codeStream.Emit(ILOpcode.localloc); codeStream.EmitStLoc(vBuffer); + codeStream.EmitLdLoca(_marshallerInstance.Value); + LoadManagedValue(codeStream); // Create ReadOnlySpan from the stack-allocated buffer @@ -1693,40 +1698,26 @@ protected override void TransformManagedToNative(ILCodeStream codeStream) codeStream.Emit(ILOpcode.newobj, emitter.NewToken(spanOfByte.GetKnownMethod(".ctor", new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), new TypeDesc[] { Context.GetWellKnownType(WellKnownType.Void).MakePointerType(), Context.GetWellKnownType(WellKnownType.Int32) })))); + codeStream.Emit(ILOpcode.call, emitter.NewToken(marshallerIn.GetKnownMethod("FromManaged", null))); - codeStream.Emit(ILOpcode.newobj, emitter.NewToken(marshaller.GetKnownMethod(".ctor", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.String), spanOfByte })))); - codeStream.EmitStLoc(_marshallerInstance.Value); + codeStream.EmitLdLoca(_marshallerInstance.Value); + codeStream.Emit(ILOpcode.call, emitter.NewToken(marshallerIn.GetKnownMethod("ToUnmanaged", null))); } else { LoadManagedValue(codeStream); - codeStream.Emit(ILOpcode.newobj, emitter.NewToken(marshaller.GetKnownMethod(".ctor", - new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), - new TypeDesc[] { Context.GetWellKnownType(WellKnownType.String) })))); - codeStream.EmitStLoc(_marshallerInstance.Value); + codeStream.Emit(ILOpcode.call, emitter.NewToken(Marshaller.GetKnownMethod("ConvertToUnmanaged", null))); } - codeStream.EmitLdLoca(_marshallerInstance.Value); - codeStream.Emit(ILOpcode.call, emitter.NewToken(marshaller.GetKnownMethod("ToNativeValue", null))); StoreNativeValue(codeStream); } protected override void TransformNativeToManaged(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; - TypeDesc marshaller = Marshaller; - if (_marshallerInstance == null) - _marshallerInstance = emitter.NewLocal(marshaller); - - codeStream.EmitLdLoca(_marshallerInstance.Value); LoadNativeValue(codeStream); - codeStream.Emit(ILOpcode.call, emitter.NewToken(marshaller.GetKnownMethod("FromNativeValue", null))); - - codeStream.EmitLdLoca(_marshallerInstance.Value); - codeStream.Emit(ILOpcode.call, emitter.NewToken(marshaller.GetKnownMethod("ToManaged", null))); + codeStream.Emit(ILOpcode.call, emitter.NewToken(Marshaller.GetKnownMethod("ConvertToManaged", null))); StoreManagedValue(codeStream); } @@ -1734,21 +1725,17 @@ protected override void EmitCleanupManaged(ILCodeStream codeStream) { ILEmitter emitter = _ilCodeStreams.Emitter; - if (In && !Out && !IsManagedByRef) + if (_marshallerInstance != null) { - Debug.Assert(_marshallerInstance != null); - codeStream.EmitLdLoca(_marshallerInstance.Value); codeStream.Emit(ILOpcode.call, emitter.NewToken( - Marshaller.GetKnownMethod("FreeNative", null))); + MarshallerIn.GetKnownMethod("Free", null))); } else { - // The marshaller instance is not guaranteed to be initialized with the latest native value. - // Free the native value directly. LoadNativeValue(codeStream); codeStream.Emit(ILOpcode.call, emitter.NewToken( - InteropTypes.GetMarshal(Context).GetKnownMethod("FreeCoTaskMem", null))); + Marshaller.GetKnownMethod("Free", null))); } } } diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index 4dd0a823930169..fa30855cbbc3cb 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -355,9 +355,6 @@ extern "C" void QCALLTYPE AssemblyNative_GetType(QCall::AssemblyHandle pAssembly BEGIN_QCALL; - if (!wszName) - COMPlusThrowArgumentNull(W("name"), W("ArgumentNull_String")); - BOOL prohibitAsmQualifiedName = TRUE; AssemblyBinder * pBinder = NULL; diff --git a/src/coreclr/vm/binder.cpp b/src/coreclr/vm/binder.cpp index cba59f246cfc4f..18f0f0b7009015 100644 --- a/src/coreclr/vm/binder.cpp +++ b/src/coreclr/vm/binder.cpp @@ -62,7 +62,34 @@ PTR_MethodTable CoreLibBinder::LookupClassLocal(BinderClassID id) const CoreLibClassDescription *d = m_classDescriptions + (int)id; - pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), d->nameSpace, d->name).AsMethodTable(); + LPCUTF8 nameSpace = d->nameSpace; + LPCUTF8 name = d->name; + + LPCUTF8 nestedTypeMaybe = strchr(name, '+'); + if (nestedTypeMaybe == NULL) + { + NameHandle nameHandle = NameHandle(nameSpace, name); + pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), &nameHandle).AsMethodTable(); + } + else + { + // Handle the nested type scenario. + // The same NameHandle must be used to retain the scope to look for the nested type. + NameHandle nameHandle(GetModule(), mdtBaseType); + + SString splitName(SString::Utf8, name, (COUNT_T)(nestedTypeMaybe - name)); + nameHandle.SetName(nameSpace, splitName.GetUTF8()); + + // The side-effect of updating the scope in the NameHandle is the point of the call. + (void)ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), &nameHandle); + + // Now load the nested type. + nameHandle.SetName(NULL, nestedTypeMaybe + 1); + + // We don't support nested types in nested types. + _ASSERTE(strchr(nameHandle.GetName(), '+') == NULL); + pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), &nameHandle).AsMethodTable(); + } _ASSERTE(pMT->GetModule() == GetModule()); diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index daebf64ea9f30e..1ca24e7fbfc09c 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -275,7 +275,6 @@ BOOL ClassLoader::IsTypicalInstantiation(Module *pModule, mdToken token, Instant return TRUE; } -// External class loader entry point: load a type by name /*static*/ TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, LPCUTF8 nameSpace, @@ -283,6 +282,18 @@ TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, NotFoundAction fNotFound, ClassLoader::LoadTypesFlag fLoadTypes, ClassLoadLevel level) +{ + WRAPPER_NO_CONTRACT; + NameHandle nameHandle(nameSpace, name); + return LoadTypeByNameThrowing(pAssembly, &nameHandle, fNotFound, fLoadTypes, level); +} + +/*static*/ +TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, + NameHandle *pNameHandle, + NotFoundAction fNotFound, + ClassLoader::LoadTypesFlag fLoadTypes, + ClassLoadLevel level) { CONTRACT(TypeHandle) { @@ -294,6 +305,7 @@ TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); } PRECONDITION(CheckPointer(pAssembly)); + PRECONDITION(pNameHandle != NULL); PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED); POSTCONDITION(CheckPointer(RETVAL, (fNotFound == ThrowIfNotFound && fLoadTypes == LoadTypes )? NULL_NOT_OK : NULL_OK)); @@ -305,13 +317,14 @@ TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, } CONTRACT_END - NameHandle nameHandle(nameSpace, name); - if (fLoadTypes == DontLoadTypes) - nameHandle.SetTokenNotToLoad(tdAllTypes); - if (fNotFound == ThrowIfNotFound) - RETURN pAssembly->GetLoader()->LoadTypeHandleThrowIfFailed(&nameHandle, level); + if (fLoadTypes == ClassLoader::DontLoadTypes) + pNameHandle->SetTokenNotToLoad(tdAllTypes); + + ClassLoader* classLoader = pAssembly->GetLoader(); + if (fNotFound == ClassLoader::ThrowIfNotFound) + RETURN classLoader->LoadTypeHandleThrowIfFailed(pNameHandle, level); else - RETURN pAssembly->GetLoader()->LoadTypeHandleThrowing(&nameHandle, level); + RETURN classLoader->LoadTypeHandleThrowing(pNameHandle, level); } #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/clsload.hpp b/src/coreclr/vm/clsload.hpp index e446e239350aff..d3e6ac20576c7b 100644 --- a/src/coreclr/vm/clsload.hpp +++ b/src/coreclr/vm/clsload.hpp @@ -699,7 +699,9 @@ class ClassLoader LoadTypesFlag fLoadTypes = LoadTypes, ClassLoadLevel level = CLASS_LOADED); - // Load types by name + // External class loader entry point + // Load types by name - doesn't support nested types. + // See overload using NameHandle. static TypeHandle LoadTypeByNameThrowing(Assembly *pAssembly, LPCUTF8 nameSpace, LPCUTF8 name, @@ -707,6 +709,13 @@ class ClassLoader LoadTypesFlag fLoadTypes = LoadTypes, ClassLoadLevel level = CLASS_LOADED); + // Load types using a NameHandle. + static TypeHandle LoadTypeByNameThrowing(Assembly *pAssembly, + NameHandle *pNameHandle, + NotFoundAction fNotFound = ThrowIfNotFound, + LoadTypesFlag fLoadTypes = LoadTypes, + ClassLoadLevel level = CLASS_LOADED); + // Resolve a TypeRef to a TypeDef // (Just a no-op on TypeDefs) // Return FALSE if operation failed (e.g. type does not exist) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index c7ea9e3c40fedd..4b170dba019198 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -74,6 +74,8 @@ // See usage in this file itself and on the link (the assembly name for feature switch in this file will be System.Private.CoreLib), // https://github.com/dotnet/designs/blob/main/accepted/2020/feature-switch.md#generate-the-right-input-for-the-linker-in-sdk // +// The FOR_ILLINK define is set when this file is being processed for the IL linker. +// #ifndef BEGIN_ILLINK_FEATURE_SWITCH #define BEGIN_ILLINK_FEATURE_SWITCH(featureName, featureValue, featureDefault) #endif @@ -1188,12 +1190,19 @@ DEFINE_METHOD(ICASTABLEHELPERS, GETIMPLTYPE, GetImplType, SM_ICast #endif // FEATURE_ICASTABLE DEFINE_CLASS(UTF8STRINGMARSHALLER, Marshalling, Utf8StringMarshaller) -DEFINE_METHOD(UTF8STRINGMARSHALLER, CTOR, .ctor, IM_Str_RetVoid) -DEFINE_METHOD(UTF8STRINGMARSHALLER, CTOR_SPAN, .ctor, IM_Str_SpanOfByte_RetVoid) -DEFINE_METHOD(UTF8STRINGMARSHALLER, TO_NATIVE_VALUE, ToNativeValue, IM_RetPtrByte) -DEFINE_METHOD(UTF8STRINGMARSHALLER, FROM_NATIVE_VALUE, FromNativeValue, IM_PtrByte_RetVoid) -DEFINE_METHOD(UTF8STRINGMARSHALLER, TO_MANAGED, ToManaged, IM_RetStr) -DEFINE_METHOD(UTF8STRINGMARSHALLER, FREE_NATIVE, FreeNative, IM_RetVoid) +DEFINE_METHOD(UTF8STRINGMARSHALLER, CONVERT_TO_MANAGED, ConvertToManaged, SM_PtrByte_RetStr) +DEFINE_METHOD(UTF8STRINGMARSHALLER, CONVERT_TO_UNMANAGED, ConvertToUnmanaged, SM_Str_RetPtrByte) +DEFINE_METHOD(UTF8STRINGMARSHALLER, FREE, Free, SM_PtrByte_RetVoid) + +// The generator for the linker XML doesn't understand inner classes so generation +// needs to skip the following type. +// See https://github.com/dotnet/runtime/issues/71847 +#ifndef FOR_ILLINK +DEFINE_CLASS(UTF8STRINGMARSHALLER_IN, Marshalling, Utf8StringMarshaller+ManagedToUnmanagedIn) +DEFINE_METHOD(UTF8STRINGMARSHALLER_IN, FROM_MANAGED, FromManaged, IM_Str_SpanOfByte_RetVoid) +DEFINE_METHOD(UTF8STRINGMARSHALLER_IN, TO_UNMANAGED, ToUnmanaged, IM_RetPtrByte) +DEFINE_METHOD(UTF8STRINGMARSHALLER_IN, FREE, Free, IM_RetVoid) +#endif // FOR_ILLINK DEFINE_CLASS(UTF8BUFFERMARSHALER, StubHelpers, UTF8BufferMarshaler) DEFINE_METHOD(UTF8BUFFERMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, NoSig) diff --git a/src/coreclr/vm/ilmarshalers.cpp b/src/coreclr/vm/ilmarshalers.cpp index 96914f90d31575..66cf2137b3c9c5 100644 --- a/src/coreclr/vm/ilmarshalers.cpp +++ b/src/coreclr/vm/ilmarshalers.cpp @@ -1958,19 +1958,24 @@ void ILCUTF8Marshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit) { STANDARD_VM_CONTRACT; - if (m_dwInstance == LOCAL_NUM_UNUSED) - m_dwInstance = pslILEmit->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__UTF8STRINGMARSHALLER))); - bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags); if (bPassByValueInOnly) { + if (m_dwInstance == LOCAL_NUM_UNUSED) + m_dwInstance = pslILEmit->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__UTF8STRINGMARSHALLER_IN))); + DWORD dwBuffer = pslILEmit->NewLocal(ELEMENT_TYPE_I); pslILEmit->EmitLDC(LOCAL_BUFFER_LENGTH); pslILEmit->EmitLOCALLOC(); pslILEmit->EmitSTLOC(dwBuffer); + // Load the marshaller instance. + pslILEmit->EmitLDLOCA(m_dwInstance); + + // Argument 1 EmitLoadManagedValue(pslILEmit); + // Argument 2 // Create ReadOnlySpan from the stack-allocated buffer pslILEmit->EmitLDLOC(dwBuffer); pslILEmit->EmitLDC(LOCAL_BUFFER_LENGTH); @@ -1979,20 +1984,17 @@ void ILCUTF8Marshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit) TypeHandle(CoreLibBinder::GetClass(CLASS__SPAN)).Instantiate(Instantiation(&thByte, 1)).AsMethodTable(), FALSE, Instantiation(), FALSE); pslILEmit->EmitNEWOBJ(pslILEmit->GetToken(pSpanCtor), 2); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__FROM_MANAGED, 2, 0); - pslILEmit->EmitNEWOBJ(METHOD__UTF8STRINGMARSHALLER__CTOR_SPAN, 2); - pslILEmit->EmitSTLOC(m_dwInstance); - + pslILEmit->EmitLDLOCA(m_dwInstance); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__TO_UNMANAGED, 1, 1); } else { EmitLoadManagedValue(pslILEmit); - pslILEmit->EmitNEWOBJ(METHOD__UTF8STRINGMARSHALLER__CTOR, 1); - pslILEmit->EmitSTLOC(m_dwInstance); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__CONVERT_TO_UNMANAGED, 1, 1); } - pslILEmit->EmitLDLOCA(m_dwInstance); - pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__TO_NATIVE_VALUE, 1, 1); EmitStoreNativeValue(pslILEmit); } @@ -2000,15 +2002,8 @@ void ILCUTF8Marshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit) { STANDARD_VM_CONTRACT; - if (m_dwInstance == LOCAL_NUM_UNUSED) - m_dwInstance = pslILEmit->NewLocal(LocalDesc(CoreLibBinder::GetClass(CLASS__UTF8STRINGMARSHALLER))); - - pslILEmit->EmitLDLOCA(m_dwInstance); EmitLoadNativeValue(pslILEmit); - pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__FROM_NATIVE_VALUE, 2, 0); - - pslILEmit->EmitLDLOCA(m_dwInstance); - pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__TO_MANAGED, 1, 1); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__CONVERT_TO_MANAGED, 1, 1); EmitStoreManagedValue(pslILEmit); } @@ -2016,20 +2011,15 @@ void ILCUTF8Marshaler::EmitClearNative(ILCodeStream* pslILEmit) { STANDARD_VM_CONTRACT; - bool bPassByValueInOnly = IsIn(m_dwMarshalFlags) && !IsOut(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags); - if (bPassByValueInOnly) + if (m_dwInstance != LOCAL_NUM_UNUSED) { - _ASSERTE(m_dwInstance != LOCAL_NUM_UNUSED); - pslILEmit->EmitLDLOCA(m_dwInstance); - pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__FREE_NATIVE, 1, 0); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER_IN__FREE, 0, 0); } else { - // The marshaller instance is not guaranteed to be initialized with the latest native value. - // Free the native value directly. EmitLoadNativeValue(pslILEmit); - pslILEmit->EmitCALL(METHOD__MARSHAL__FREE_CO_TASK_MEM, 1, 0); + pslILEmit->EmitCALL(METHOD__UTF8STRINGMARSHALLER__FREE, 1, 0); } } diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 5b5bfc2d42746d..f567d34be2f7da 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -426,7 +426,6 @@ DEFINE_METASIG_T(SM(PtrSByt_Int_Int_Encoding_RetStr, P(B) i i C(ENCODING), s)) DEFINE_METASIG(IM(Obj_Int_RetIntPtr, j i, I)) DEFINE_METASIG(IM(ArrByte_Int_Int_RetVoid, a(b) i i, v)) -DEFINE_METASIG(IM(PtrByte_RetVoid, P(b), v)) DEFINE_METASIG(IM(Char_Char_RetStr, u u, s)) DEFINE_METASIG(IM(Char_Int_RetVoid, u i, v)) @@ -491,7 +490,6 @@ DEFINE_METASIG_T(SM(Str_CultureInfo_RetStr, s C(CULTURE_INFO), s)) DEFINE_METASIG_T(SM(Str_CultureInfo_RefBool_RetStr, s C(CULTURE_INFO) r(F), s)) DEFINE_METASIG(SM(PtrPtrChar_PtrPtrChar_Int_RetVoid, P(P(u)) P(P(u)) i, v)) DEFINE_METASIG(SM(PtrChar_Int_PtrPtrChar_RetArrStr, P(u) i P(P(u)), a(s))) -DEFINE_METASIG(IM(Str_RetVoid, s, v)) DEFINE_METASIG(SM(RefBool_RefBool_RetVoid, r(F) r(F), v)) DEFINE_METASIG_T(IM(Str_Exception_RetVoid, s C(EXCEPTION), v)) DEFINE_METASIG(IM(Str_Obj_RetVoid, s j, v)) @@ -615,6 +613,10 @@ DEFINE_METASIG_T(IM(Str_SpanOfByte_RetVoid, s GI(g(SPAN), 1, b), v)) DEFINE_METASIG(IM(RetPtrByte, , P(b))) DEFINE_METASIG(IM(VoidPtr_Int_RetVoid, P(v) i, v)) +DEFINE_METASIG(SM(PtrByte_RetStr, P(b), s)) +DEFINE_METASIG(SM(Str_RetPtrByte, s, P(b))) +DEFINE_METASIG(SM(PtrByte_RetVoid, P(b), v)) + // Undefine macros in case we include the file again in the compilation unit #undef DEFINE_METASIG diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml index f04aeb1fa84586..0f577d8253d599 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml @@ -74,5 +74,12 @@ + + + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/AnsiStringMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/AnsiStringMarshaller.cs index 5baea94b9372d4..7161dc4ee20ad4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/AnsiStringMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/AnsiStringMarshaller.cs @@ -9,90 +9,103 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for ANSI strings /// [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(string), BufferSize = 0x100, - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer)] - public unsafe ref struct AnsiStringMarshaller + [CustomMarshaller(typeof(string), MarshalMode.Default, typeof(AnsiStringMarshaller))] + [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanagedIn))] + public static unsafe class AnsiStringMarshaller { - private byte* _nativeValue; - private bool _allocated; + /// + /// Convert a string to an unmanaged version. + /// + /// A managed string + /// An unmanaged string + 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 buffer = new (mem, exactByteCount); + + Marshal.GetAnsiStringBytes(managed, buffer); // Includes null terminator + return mem; + } + + /// + /// Convert an unmanaged string to a managed version. + /// + /// An unmanaged string + /// A managed string + public static string? ConvertToManaged(byte* unmanaged) + => Marshal.PtrToStringAnsi((IntPtr)unmanaged); /// - /// Initializes a new instance of the . + /// Free the memory for the unmanaged string. /// - /// The string to marshal. - public AnsiStringMarshaller(string? str) - : this(str, default) - { } + /// Memory allocated for the unmanaged string. + public static void Free(byte* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); /// - /// Initializes a new instance of the . + /// Custom marshaller to marshal a managed string as a ANSI unmanaged string. /// - /// The string to marshal. - /// Buffer that may be used for marshalling. - /// - /// The must not be movable - that is, it should not be - /// on the managed heap or it should be pinned. - /// - /// - public AnsiStringMarshaller(string? str, Span buffer) + public ref struct ManagedToUnmanagedIn { - _allocated = false; + /// + /// Requested buffer size for optimized marshalling. + /// + public static int BufferSize => 0x100; - if (str is null) - { - _nativeValue = null; - return; - } + private byte* _unmanagedValue; + private bool _allocated; - // >= for null terminator - // Use the cast to long to avoid the checked operation - if ((long)Marshal.SystemMaxDBCSCharSize * str.Length >= buffer.Length) + /// + /// Initialize the marshaller with a managed string and requested buffer. + /// + /// The managed string + /// A request buffer of at least size, . + public void FromManaged(string? managed, Span buffer) { - // 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) + _allocated = false; + + if (managed is null) { - buffer = new Span((byte*)Marshal.AllocCoTaskMem(exactByteCount), exactByteCount); - _allocated = true; + _unmanagedValue = null; + return; } - } - - _nativeValue = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); - Marshal.GetAnsiStringBytes(str, buffer); // Includes null terminator - } + // >= 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*)NativeMemory.Alloc((nuint)exactByteCount), exactByteCount); + _allocated = true; + } + } - /// - /// Returns the native value representing the string. - /// - /// - public byte* ToNativeValue() => _nativeValue; + _unmanagedValue = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); - /// - /// Sets the native value representing the string. - /// - /// The native value. - /// - public void FromNativeValue(byte* value) - { - _nativeValue = value; - _allocated = true; - } + Marshal.GetAnsiStringBytes(managed, buffer); // Includes null terminator + } - /// - /// Returns the managed string. - /// - /// - public string? ToManaged() => Marshal.PtrToStringAnsi((IntPtr)_nativeValue); + /// + /// Convert the current manage string to an unmanaged string. + /// + /// The unmanaged string + public byte* ToUnmanaged() => _unmanagedValue; - /// - /// Frees native resources. - /// - /// - public void FreeNative() - { - if (_allocated) - Marshal.FreeCoTaskMem((IntPtr)_nativeValue); + /// + /// Free any allocated unmanaged string. + /// + public void Free() + { + if (_allocated) + NativeMemory.Free(_unmanagedValue); + } } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/BStrStringMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/BStrStringMarshaller.cs index 4f246a26bc3265..4febd95b275a55 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/BStrStringMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/BStrStringMarshaller.cs @@ -11,107 +11,109 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for BSTR strings /// [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(string), BufferSize = 0x100, - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer)] - public unsafe ref struct BStrStringMarshaller + [CustomMarshaller(typeof(string), MarshalMode.Default, typeof(BStrStringMarshaller))] + [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanagedIn))] + public static unsafe class BStrStringMarshaller { - private void* _ptrToFirstChar; - private bool _allocated; - /// - /// Initializes a new instance of the . + /// Convert a string to an unmanaged version. /// - /// The string to marshal. - public BStrStringMarshaller(string? str) - : this(str, default) - { } + /// A managed string + /// An unmanaged string + public static ushort* ConvertToUnmanaged(string? managed) + => (ushort*)Marshal.StringToBSTR(managed); /// - /// Initializes a new instance of the . + /// Convert an unmanaged string to a managed version. /// - /// The string to marshal. - /// Buffer that may be used for marshalling. - /// - /// The must not be movable - that is, it should not be - /// on the managed heap or it should be pinned. - /// - /// - public BStrStringMarshaller(string? str, Span buffer) + /// An unmanaged string + /// A managed string + public static string? ConvertToManaged(ushort* unmanaged) { - _allocated = false; - - if (str is null) - { - _ptrToFirstChar = null; - return; - } - - ushort* ptrToFirstChar; - int lengthInBytes = checked(sizeof(char) * str.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)); + if (unmanaged is null) + return null; - // Copy characters from the managed string - str.CopyTo(new Span(ptrToFirstChar, str.Length)); - ptrToFirstChar[str.Length] = '\0'; // null-terminate - _ptrToFirstChar = ptrToFirstChar; + return Marshal.PtrToStringBSTR((IntPtr)unmanaged); } /// - /// Returns the native value representing the string. + /// Free the memory for the unmanaged string. /// - /// - public void* ToNativeValue() => _ptrToFirstChar; + /// Memory allocated for the unmanaged string. + public static void Free(ushort* unmanaged) + => Marshal.FreeBSTR((IntPtr)unmanaged); /// - /// Sets the native value representing the string. + /// Custom marshaller to marshal a managed string as a ANSI unmanaged string. /// - /// The native value. - /// - public void FromNativeValue(void* value) + public ref struct ManagedToUnmanagedIn { - _ptrToFirstChar = value; - _allocated = true; - } + /// + /// Requested buffer size for optimized marshalling. + /// + public static int BufferSize => 0x100; - /// - /// Returns the managed string. - /// - /// - public string? ToManaged() - { - if (_ptrToFirstChar is null) - return null; + private ushort* _ptrToFirstChar; + private bool _allocated; - return Marshal.PtrToStringBSTR((IntPtr)_ptrToFirstChar); - } + /// + /// Initialize the marshaller with a managed string and requested buffer. + /// + /// The managed string + /// A request buffer of at least size, . + public void FromManaged(string? managed, Span buffer) + { + _allocated = false; - /// - /// Frees native resources. - /// - /// - public void FreeNative() - { - if (_allocated) - Marshal.FreeBSTR((IntPtr)_ptrToFirstChar); + 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(ptrToFirstChar, managed.Length)); + ptrToFirstChar[managed.Length] = '\0'; // null-terminate + _ptrToFirstChar = ptrToFirstChar; + } + + /// + /// Convert the current manage string to an unmanaged string. + /// + /// The unmanaged string + public ushort* ToUnmanaged() => _ptrToFirstChar; + + /// + /// Free any allocated unmanaged string. + /// + public void Free() + { + if (_allocated) + BStrStringMarshaller.Free(_ptrToFirstChar); + } } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf16StringMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf16StringMarshaller.cs index 22d317a9cb17d2..e8058e7f8df4c7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf16StringMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf16StringMarshaller.cs @@ -9,51 +9,38 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for UTF-16 strings /// [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(string), - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe ref struct Utf16StringMarshaller + [CustomMarshaller(typeof(string), MarshalMode.Default, typeof(Utf16StringMarshaller))] + public static unsafe class Utf16StringMarshaller { - private void* _nativeValue; - - /// - /// Initializes a new instance of the . - /// - /// - /// The caller allocated constructor option is not provided because - /// pinning should be preferred for UTF-16 scenarios. - /// - /// The string to marshal. - public Utf16StringMarshaller(string? str) - { - _nativeValue = (void*)Marshal.StringToCoTaskMemUni(str); - } - /// - /// Returns the native value representing the string. + /// Convert a string to an unmanaged version. /// - /// - public void* ToNativeValue() => _nativeValue; + /// A managed string + /// An unmanaged string + public static ushort* ConvertToUnmanaged(string? managed) + => (ushort*)Marshal.StringToCoTaskMemUni(managed); /// - /// Sets the native value representing the string. + /// Convert an unmanaged string to a managed version. /// - /// The native value. - /// - public void FromNativeValue(void* value) => _nativeValue = value; + /// An unmanaged string + /// A managed string + public static string? ConvertToManaged(ushort* unmanaged) + => Marshal.PtrToStringUni((IntPtr)unmanaged); /// - /// Returns the managed string. + /// Free the memory for the unmanaged string. /// - /// - public string? ToManaged() => Marshal.PtrToStringUni((IntPtr)_nativeValue); + /// Memory allocated for the unmanaged string. + public static void Free(ushort* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); /// - /// Frees native resources. + /// Get a pinnable reference for the string. /// - /// - public void FreeNative() - { - Marshal.FreeCoTaskMem((IntPtr)_nativeValue); - } + /// The string. + /// A pinnable reference. + public static ref readonly char GetPinnableReference(string? str) + => ref str is null ? ref *(char*)0 : ref str.GetPinnableReference(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf8StringMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf8StringMarshaller.cs index 955e6b7b62f70f..a413349e4e4f29 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf8StringMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/Utf8StringMarshaller.cs @@ -10,93 +10,107 @@ namespace System.Runtime.InteropServices.Marshalling /// Marshaller for UTF-8 strings /// [CLSCompliant(false)] - [CustomTypeMarshaller(typeof(string), BufferSize = 0x100, - Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer)] - public unsafe ref struct Utf8StringMarshaller + [CustomMarshaller(typeof(string), MarshalMode.Default, typeof(Utf8StringMarshaller))] + [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanagedIn))] + public static unsafe class Utf8StringMarshaller { - private byte* _nativeValue; - private bool _allocated; + /// + /// Convert a string to an unmanaged version. + /// + /// A managed string + /// An unmanaged string + public static byte* ConvertToUnmanaged(string? managed) + { + if (managed is null) + return null; + + int exactByteCount = checked(Encoding.UTF8.GetByteCount(managed) + 1); // + 1 for null terminator + byte* mem = (byte*)Marshal.AllocCoTaskMem(exactByteCount); + Span buffer = new (mem, exactByteCount); + + int byteCount = Encoding.UTF8.GetBytes(managed, buffer); + buffer[byteCount] = 0; // null-terminate + return mem; + } /// - /// Initializes a new instance of the . + /// Convert an unmanaged string to a managed version. /// - /// The string to marshal. - public Utf8StringMarshaller(string? str) - : this(str, default) - { } + /// An unmanaged string + /// A managed string + public static string? ConvertToManaged(byte* unmanaged) + => Marshal.PtrToStringUTF8((IntPtr)unmanaged); /// - /// Initializes a new instance of the . + /// Free the memory for the unmanaged string. /// - /// The string to marshal. - /// Buffer that may be used for marshalling. - /// - /// The must not be movable - that is, it should not be - /// on the managed heap or it should be pinned. - /// - /// - public Utf8StringMarshaller(string? str, Span buffer) - { - _allocated = false; + /// Memory allocated for the unmanaged string. + public static void Free(byte* unmanaged) + => Marshal.FreeCoTaskMem((IntPtr)unmanaged); - if (str is null) - { - _nativeValue = null; - return; - } + /// + /// Custom marshaller to marshal a managed string as a UTF-8 unmanaged string. + /// + public ref struct ManagedToUnmanagedIn + { + /// + /// Requested buffer size for optimized marshalling. + /// + public static int BufferSize => 0x100; - const int MaxUtf8BytesPerChar = 3; + private byte* _unmanagedValue; + private bool _allocated; - // >= for null terminator - // Use the cast to long to avoid the checked operation - if ((long)MaxUtf8BytesPerChar * str.Length >= buffer.Length) + /// + /// Initialize the marshaller with a managed string and requested buffer. + /// + /// The managed string + /// A request buffer of at least size, . + public void FromManaged(string? managed, Span buffer) { - // Calculate accurate byte count when the provided stack-allocated buffer is not sufficient - int exactByteCount = checked(Encoding.UTF8.GetByteCount(str) + 1); // + 1 for null terminator - if (exactByteCount > buffer.Length) + _allocated = false; + + if (managed is null) { - buffer = new Span((byte*)Marshal.AllocCoTaskMem(exactByteCount), exactByteCount); - _allocated = true; + _unmanagedValue = null; + return; } - } - _nativeValue = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); + const int MaxUtf8BytesPerChar = 3; - int byteCount = Encoding.UTF8.GetBytes(str, buffer); - buffer[byteCount] = 0; // null-terminate - } + // >= for null terminator + // Use the cast to long to avoid the checked operation + if ((long)MaxUtf8BytesPerChar * managed.Length >= buffer.Length) + { + // Calculate accurate byte count when the provided stack-allocated buffer is not sufficient + int exactByteCount = checked(Encoding.UTF8.GetByteCount(managed) + 1); // + 1 for null terminator + if (exactByteCount > buffer.Length) + { + buffer = new Span((byte*)NativeMemory.Alloc((nuint)exactByteCount), exactByteCount); + _allocated = true; + } + } - /// - /// Returns the native value representing the string. - /// - /// - public byte* ToNativeValue() => _nativeValue; + _unmanagedValue = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); - /// - /// Sets the native value representing the string. - /// - /// The native value. - /// - public void FromNativeValue(byte* value) - { - _nativeValue = value; - _allocated = true; - } + int byteCount = Encoding.UTF8.GetBytes(managed, buffer); + buffer[byteCount] = 0; // null-terminate + } - /// - /// Returns the managed string. - /// - /// - public string? ToManaged() => Marshal.PtrToStringUTF8((IntPtr)_nativeValue); + /// + /// Convert the current manage string to an unmanaged string. + /// + /// The unmanaged string + public byte* ToUnmanaged() => _unmanagedValue; - /// - /// Frees native resources. - /// - /// - public void FreeNative() - { - if (_allocated) - Marshal.FreeCoTaskMem((IntPtr)_nativeValue); + /// + /// Free any allocated unmanaged string. + /// + public void Free() + { + if (_allocated) + NativeMemory.Free(_unmanagedValue); + } } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs index cf2596270e21a3..b7699f4855990f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs @@ -1257,12 +1257,13 @@ public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax return node.WithRight( CastExpression(MarshallerHelpers.SystemIntPtrType, node.Right)); } + if (node.Right.ToString() == _nativeIdentifier) { return node.WithRight(CastExpression(_nativeType, node.Right)); } - return node; + return base.VisitAssignmentExpression(node); } public override SyntaxNode? VisitArgument(ArgumentSyntax node) @@ -1272,7 +1273,8 @@ public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax return node.WithExpression( CastExpression(_nativeType, node.Expression)); } - return node; + + return base.VisitArgument(node); } } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 30706338415173..99fdb8fe666231 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2124,18 +2124,25 @@ public enum MessageSendFunction namespace System.Runtime.InteropServices.Marshalling { [System.CLSCompliant(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), BufferSize = 0x100, - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.CallerAllocatedBuffer - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling )] - public unsafe ref struct AnsiStringMarshaller - { - public AnsiStringMarshaller(string? str) { } - public AnsiStringMarshaller(string? str, System.Span buffer) { } - public byte* ToNativeValue() { throw null; } - public void FromNativeValue(byte* value) { } - public string? ToManaged() { throw null; } - public void FreeNative() { } + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller.ManagedToUnmanagedIn))] + public static unsafe class AnsiStringMarshaller + { + public static byte* ConvertToUnmanaged(string? managed) { throw null; } + public static string? ConvertToManaged(byte* unmanaged) { throw null; } + public static void Free(byte* unmanaged) { throw null; } + + public ref struct ManagedToUnmanagedIn + { + public static int BufferSize { get { throw null; } } + public void FromManaged(string? managed, System.Span buffer) { throw null; } + public byte* ToUnmanaged() { throw null; } + public void Free() { throw null; } + } } [System.CLSCompliantAttribute(false)] [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder[]), @@ -2159,20 +2166,26 @@ public void FromNativeValue(byte* value) { } public void FreeNative() { } } [System.CLSCompliant(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), BufferSize = 0x100, - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.CallerAllocatedBuffer - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling )] - public unsafe ref struct BStrStringMarshaller - { - public BStrStringMarshaller(string? str) { } - public BStrStringMarshaller(string? str, System.Span buffer) { } - public void* ToNativeValue() { throw null; } - public void FromNativeValue(void* value) { } - public string? ToManaged() { throw null; } - public void FreeNative() { } - } + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.BStrStringMarshaller))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.BStrStringMarshaller.ManagedToUnmanagedIn))] + public static unsafe class BStrStringMarshaller + { + public static ushort* ConvertToUnmanaged(string? managed) { throw null; } + public static string? ConvertToManaged(ushort* unmanaged) { throw null; } + public static void Free(ushort* unmanaged) { throw null; } + public ref struct ManagedToUnmanagedIn + { + public static int BufferSize { get { throw null; } } + public void FromManaged(string? managed, System.Span buffer) { throw null; } + public ushort* ToUnmanaged() { throw null; } + public void Free() { throw null; } + } + } [System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class, AllowMultiple = true)] public sealed partial class CustomMarshallerAttribute : System.Attribute { @@ -2272,30 +2285,36 @@ public void FromNativeValue(byte* value) { } public void FreeNative() { } } [System.CLSCompliant(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), BufferSize = 0x100, - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.CallerAllocatedBuffer - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling )] - public unsafe ref struct Utf8StringMarshaller - { - public Utf8StringMarshaller(string? str) { } - public Utf8StringMarshaller(string? str, System.Span buffer) { } - public byte* ToNativeValue() { throw null; } - public void FromNativeValue(byte* value) { } - public string? ToManaged() { throw null; } - public void FreeNative() { } + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.ManagedToUnmanagedIn, + typeof(System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller.ManagedToUnmanagedIn))] + public static unsafe class Utf8StringMarshaller + { + public static byte* ConvertToUnmanaged(string? managed) { throw null; } + public static string? ConvertToManaged(byte* unmanaged) { throw null; } + public static void Free(byte* unmanaged) { throw null; } + + public ref struct ManagedToUnmanagedIn + { + public static int BufferSize { get { throw null; } } + public void FromManaged(string? managed, System.Span buffer) { throw null; } + public byte* ToUnmanaged() { throw null; } + public void Free() { throw null; } + } } [System.CLSCompliant(false)] - [System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute(typeof(string), - Features = System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.UnmanagedResources - | System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerFeatures.TwoStageMarshalling )] - public unsafe ref struct Utf16StringMarshaller - { - public Utf16StringMarshaller(string? str) { } - public void* ToNativeValue() { throw null; } - public void FromNativeValue(void* value) { } - public string? ToManaged() { throw null; } - public void FreeNative() { } + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(string), + System.Runtime.InteropServices.Marshalling.MarshalMode.Default, + typeof(System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller))] + public static unsafe class Utf16StringMarshaller + { + public static ushort* ConvertToUnmanaged(string? managed) { throw null; } + public static string? ConvertToManaged(ushort* unmanaged) { throw null; } + public static void Free(ushort* unmanaged) { throw null; } + public static ref readonly char GetPinnableReference(string? str) { throw null; } } } namespace System.Security