From: Nikolay Sivov Date: Thu, 29 Aug 2019 12:19:09 +0000 (+0300) Subject: [cominterop] Implement native-to-managed safearray marshalling. (mono/mono#16483) X-Git-Tag: submit/tizen/20210909.063632~10331^2~5^2~649 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=10959b524677b91dccdacdac0b13f830fe519e38;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [cominterop] Implement native-to-managed safearray marshalling. (mono/mono#16483) * [cominterop] Implement native-to-managed safearray marshalling. * [tests] Fix index variable type. In attempt ot fix MSVC build failure (int* vs LONG* on Windows). * [cominterop] Use proper statement block for newly added switch entry. * [marshal] Conditionally compile in mono_cominterop_emit_marshal_safearray(). Hopefully should fix remaining build failures. * [cominterop] Don't free user array argument Commit migrated from https://github.com/mono/mono/commit/421bd79f06a92372e0259be5349e4236edf0e7bb --- diff --git a/src/mono/mono/metadata/cominterop.c b/src/mono/mono/metadata/cominterop.c index 3ea0eeb..2593947 100644 --- a/src/mono/mono/metadata/cominterop.c +++ b/src/mono/mono/metadata/cominterop.c @@ -3220,7 +3220,108 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT } break; } + case MARSHAL_ACTION_MANAGED_CONV_IN: { + if (!(t->attrs & PARAM_ATTRIBUTE_IN)) + break; + + /* Generates IL code for the following algorithm: + + Array result; // result_var + IntPtr indices; // indices_var + int empty; // empty_var + if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) { + if (!empty) { + int index=0; // index_var + do { // label3 + object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices)); + result.SetValueImpl(elem, index); + ++index; + } + while (mono_marshal_safearray_next(safearray, indices)); + } // label2 + mono_marshal_safearray_free_indices(indices); + } // label1 + */ + + int result_var, indices_var, empty_var, elem_var, index_var; + guint32 label1 = 0, label2 = 0, label3 = 0; + static MonoMethod *get_object_for_native_variant = NULL; + static MonoMethod *set_value_impl = NULL; + + MonoType *object_type = mono_get_object_type (); + MonoType *int_type = mono_get_int_type (); + result_var = mono_mb_add_local (mb, object_type); + indices_var = mono_mb_add_local (mb, int_type); + empty_var = mono_mb_add_local (mb, int_type); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, result_var); + mono_mb_emit_ldloc_addr (mb, indices_var); + mono_mb_emit_ldloc_addr (mb, empty_var); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_CONV_I); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + mono_mb_emit_icall (mb, mono_marshal_safearray_begin); + + label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + mono_mb_emit_ldloc (mb, empty_var); + + label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + + index_var = mono_mb_add_local (mb, int_type); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); + + label3 = mono_mb_get_label (mb); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_get_value); + + if (!get_object_for_native_variant) { + ERROR_DECL (error); + get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error); + mono_error_assert_ok (error); + } + g_assert (get_object_for_native_variant); + + if (!set_value_impl) { + ERROR_DECL (error); + set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error); + mono_error_assert_ok (error); + } + g_assert (set_value_impl); + + elem_var = mono_mb_add_local (mb, object_type); + + mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); + mono_mb_emit_stloc (mb, elem_var); + + mono_mb_emit_ldloc (mb, result_var); + mono_mb_emit_ldloc (mb, elem_var); + mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_managed_call (mb, set_value_impl, NULL); + + mono_mb_emit_add_to_local (mb, index_var, 1); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_next); + mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3); + + mono_mb_patch_short_branch (mb, label2); + + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices); + + mono_mb_patch_short_branch (mb, label1); + + mono_mb_emit_ldloc (mb, result_var); + mono_mb_emit_stloc (mb, conv_arg); + + break; + } default: g_assert_not_reached (); } diff --git a/src/mono/mono/metadata/marshal-ilgen.c b/src/mono/mono/metadata/marshal-ilgen.c index 809481d..0f126a0 100644 --- a/src/mono/mono/metadata/marshal-ilgen.c +++ b/src/mono/mono/metadata/marshal-ilgen.c @@ -2577,11 +2577,25 @@ emit_marshal_array_ilgen (EmitMarshalContext *m, int argnum, MonoType *t, char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code."); mono_mb_emit_exception_marshal_directive (mb, msg); return conv_arg; - } - if (spec->native != MONO_NATIVE_LPARRAY) { - char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented."); + } + + switch (spec->native) { + case MONO_NATIVE_LPARRAY: + break; + case MONO_NATIVE_SAFEARRAY: +#ifndef DISABLE_COM + if (spec->data.safearray_data.elem_type != MONO_VARIANT_VARIANT) { + char *msg = g_strdup ("Only SAFEARRAY(VARIANT) marshalling to managed code is implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + return conv_arg; + } + return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif + default: { + char *msg = g_strdup ("Unsupported array type marshalling to managed code."); mono_mb_emit_exception_marshal_directive (mb, msg); - return conv_arg; + return conv_arg; + } } /* FIXME: t is from the method which is wrapped, not the delegate type */ @@ -6026,7 +6040,6 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s case MONO_TYPE_STRING: case MONO_TYPE_BOOLEAN: tmp_locals [i] = mono_emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN); - break; default: tmp_locals [i] = 0; diff --git a/src/mono/mono/tests/cominterop.cs b/src/mono/mono/tests/cominterop.cs index 2afac90..6c26107 100644 --- a/src/mono/mono/tests/cominterop.cs +++ b/src/mono/mono/tests/cominterop.cs @@ -322,6 +322,9 @@ public class Tests [In, Out, MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] ref Array array4); [DllImport("libtest")] + public static extern int mono_test_marshal_safearray_in_ccw([MarshalAs (UnmanagedType.Interface)] ITest itest); + + [DllImport("libtest")] public static extern bool mono_cominterop_is_supported (); public static int Main () @@ -606,7 +609,6 @@ public class Tests if (isWindows) { /* out */ - Array array; if ((mono_test_marshal_safearray_out_1dim_vt_bstr_empty (out array) != 0) || (array.Rank != 1) || (array.Length != 0)) return 62; @@ -762,6 +764,8 @@ public class Tests if (i != Convert.ToInt32 (array4.GetValue (i))) return 96; } + if (mono_test_marshal_safearray_in_ccw(test) != 0) + return 97; } #endregion // SafeArray Tests @@ -817,6 +821,8 @@ public class Tests int Return22NoICall(); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] int IntOut(); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ArrayIn ([In, MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] array); } [ComImport ()] @@ -873,6 +879,8 @@ public class Tests [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [PreserveSig ()] int IntOut (out int val); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + int ArrayIn ([In, MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] array); } [System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")] @@ -916,6 +924,8 @@ public class Tests public virtual extern int Return22NoICall(); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public virtual extern int IntOut(); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ArrayIn ([In, MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] array); } [System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")] @@ -1066,6 +1076,34 @@ public class Tests val = 33; return 0; } + + public int ArrayIn(object[] array) + { + if (array.Length != 2) + return 40; + if (array.Rank != 1) + return 41; + if (array.GetLowerBound(0) != 0) + return 42; + if (array.GetUpperBound(0) != 1) + return 43; + if (array[0] is string) + { + if ((array[0] as string) != "Test") + return 44; + } + else + return 45; + if (array[1] is int) + { + if ((int)array[1] != 2345) + return 46; + } + else + return 47; + + return 444; + } } public class ManagedTest : ITest @@ -1165,6 +1203,30 @@ public class Tests { return 33; } + + public void ArrayIn(object[] array) + { + if (array.Length != 2) + status = 40; + else if (array.Rank != 1) + status = 41; + else if (array.GetLowerBound(0) != 0) + status = 42; + else if (array.GetUpperBound(0) != 1) + status = 43; + else if (array[0] is string) + { + if ((array[0] as string) != "Test") + status = 44; + } + else if (array[1] is int) + { + if ((int)array[1] != 2345) + status = 45; + } + + status = 444; + } } [ComVisible (true)] diff --git a/src/mono/mono/tests/libtest.c b/src/mono/mono/tests/libtest.c index d4c5ade..782edd3 100644 --- a/src/mono/mono/tests/libtest.c +++ b/src/mono/mono/tests/libtest.c @@ -3390,6 +3390,7 @@ typedef struct int (STDCALL *ITestOut)(MonoComObject* pUnk, MonoComObject* *ppUnk); int (STDCALL *Return22NoICall)(MonoComObject* pUnk); int (STDCALL *IntOut)(MonoComObject* pUnk, int *a); + int (STDCALL *ArrayIn)(MonoComObject* pUnk, void *array); } MonoIUnknown; struct MonoComObject @@ -3519,6 +3520,12 @@ IntOut(MonoComObject* pUnk, int *a) return S_OK; } +LIBTEST_API int STDCALL +ArrayIn(MonoComObject* pUnk, void *array) +{ + return S_OK; +} + static void create_com_object (MonoComObject** pOut); LIBTEST_API int STDCALL @@ -3552,6 +3559,7 @@ static void create_com_object (MonoComObject** pOut) (*pOut)->vtbl->get_ITest = get_ITest; (*pOut)->vtbl->Return22NoICall = Return22NoICall; (*pOut)->vtbl->IntOut = IntOut; + (*pOut)->vtbl->ArrayIn = ArrayIn; } static MonoComObject* same_object = NULL; @@ -5557,6 +5565,33 @@ mono_test_marshal_safearray_mixed( return hr; } +LIBTEST_API int STDCALL +mono_test_marshal_safearray_in_ccw(MonoComObject *pUnk) +{ + SAFEARRAY *array; + VARIANT var; + long index; + int ret; + + array = SafeArrayCreateVector(VT_VARIANT, 0, 2); + + var.vt = VT_BSTR; + var.bstrVal = marshal_bstr_alloc("Test"); + index = 0; + SafeArrayPutElement(array, &index, &var); + + var.vt = VT_I4; + var.intVal = 2345; + index = 1; + SafeArrayPutElement(array, &index, &var); + + ret = pUnk->vtbl->ArrayIn (pUnk, (void *)array); + + SafeArrayDestroy(array); + + return ret; +} + #endif static int call_managed_res;