* Use string constructor that takes length instead of the one that searches for a null terminator.
Fixes #54662
* Marshal back buffer size or string to first null terminator, whichever is shorter
* Add tests.
* Add unicode test.
* Use the same implementation style for the wstr case case as the cstr case
* Fix accidental deletion from test.
managed.Slice(0, numChars).CopyTo(native);
native[numChars] = '\0';
}
+
+ internal static unsafe string ConvertToManaged(IntPtr nativeHome, int length)
+ {
+ int end = SpanHelpers.IndexOf(ref *(char*)nativeHome, '\0', length);
+ if (end != -1)
+ {
+ length = end;
+ }
+
+ return new string((char*)nativeHome, 0, length);
+ }
} // class WSTRBufferMarshaler
#if FEATURE_COMINTEROP
DEFINE_CLASS(FIXEDWSTRMARSHALER, StubHelpers, FixedWSTRMarshaler)
DEFINE_METHOD(FIXEDWSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_Str_IntPtr_Int_RetVoid)
+DEFINE_METHOD(FIXEDWSTRMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, SM_IntPtr_Int_RetStr)
DEFINE_CLASS(BSTRMARSHALER, StubHelpers, BSTRMarshaler)
DEFINE_METHOD(BSTRMARSHALER, CONVERT_TO_NATIVE, ConvertToNative, SM_Str_IntPtr_RetIntPtr)
STANDARD_VM_CONTRACT;
EmitLoadNativeHomeAddr(pslILEmit);
- pslILEmit->EmitDUP();
- pslILEmit->EmitCALL(METHOD__STRING__WCSLEN, 1, 1);
- pslILEmit->EmitCALL(METHOD__STUBHELPERS__CHECK_STRING_LENGTH, 1, 0);
-
- pslILEmit->EmitNEWOBJ(METHOD__STRING__CTOR_CHARPTR, 1);
+ pslILEmit->EmitLDC(m_pargs->fs.fixedStringLength);
+ pslILEmit->EmitCALL(METHOD__FIXEDWSTRMARSHALER__CONVERT_TO_MANAGED, 2, 1);
EmitStoreManagedValue(pslILEmit);
}
class LPTStrTest
{
private static readonly string InitialString = "Hello World";
+ private static readonly string LongString = "0123456789abcdefghi";
+ private static readonly string LongUnicodeString = "๐จโ๐จโ๐งโ๐ง๐ฑโ๐ค";
public static int Main()
{
};
ReverseByValStringUni(ref uniStr);
-
Assert.AreEqual(Helpers.Reverse(InitialString), uniStr.str);
+
+ ReverseCopyByValStringAnsi(new ByValStringInStructAnsi { str = LongString }, out ByValStringInStructSplitAnsi ansiStrSplit);
+
+ Assert.AreEqual(Helpers.Reverse(LongString[^10..]), ansiStrSplit.str1);
+ Assert.AreEqual(Helpers.Reverse(LongString[..^10]), ansiStrSplit.str2);
+
+ ReverseCopyByValStringUni(new ByValStringInStructUnicode { str = LongString }, out ByValStringInStructSplitUnicode uniStrSplit);
+
+ Assert.AreEqual(Helpers.Reverse(LongString[^10..]), uniStrSplit.str1);
+ Assert.AreEqual(Helpers.Reverse(LongString[..^10]), uniStrSplit.str2);
+
+ ReverseCopyByValStringUni(new ByValStringInStructUnicode { str = LongUnicodeString }, out ByValStringInStructSplitUnicode uniStrSplit2);
+
+ Assert.AreEqual(Helpers.Reverse(LongUnicodeString[^10..]), uniStrSplit2.str1);
+ Assert.AreEqual(Helpers.Reverse(LongUnicodeString[..^10]), uniStrSplit2.str2);
}
}
{
StringMarshalingTests<LPWSTR, TP_slen>::ReverseInplace(str->str);
}
+
+extern "C" DLL_EXPORT void STDMETHODCALLTYPE ReverseCopyByValStringAnsi(ByValStringInStructAnsi str, ByValStringInStructAnsi* out)
+{
+ *out = str;
+ StringMarshalingTests<char*, default_callconv_strlen>::ReverseInplace(out->str);
+}
+
+extern "C" DLL_EXPORT void STDMETHODCALLTYPE ReverseCopyByValStringUni(ByValStringInStructUnicode str, ByValStringInStructUnicode* out)
+{
+ *out = str;
+ StringMarshalingTests<LPWSTR, TP_slen>::ReverseInplace(out->str);
+}
public string str;
}
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct ByValStringInStructSplitAnsi
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
+ public string str1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
+ public string str2;
+ }
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ByValStringInStructUnicode
{
public string str;
}
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct ByValStringInStructSplitUnicode
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
+ public string str1;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
+ public string str2;
+ }
+
[DllImport(nameof(LPTStrTestNative), CharSet = CharSet.Unicode)]
public static extern bool Verify_NullTerminators_PastEnd(StringBuilder builder, int length);
public static extern void ReverseByValStringAnsi(ref ByValStringInStructAnsi str);
[DllImport(nameof(LPTStrTestNative))]
public static extern void ReverseByValStringUni(ref ByValStringInStructUnicode str);
+
+ [DllImport(nameof(LPTStrTestNative))]
+ public static extern void ReverseCopyByValStringAnsi(ByValStringInStructAnsi str, out ByValStringInStructSplitAnsi strOut);
+ [DllImport(nameof(LPTStrTestNative))]
+ public static extern void ReverseCopyByValStringUni(ByValStringInStructUnicode str, out ByValStringInStructSplitUnicode strOut);
}