PageRenderTime 75ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/mono/metadata/cominterop.c

https://bitbucket.org/danipen/mono
C | 3273 lines | 2419 code | 542 blank | 312 comment | 488 complexity | a506d20713f76ccb42e6917e38488493 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /*
  2. * cominterop.c: COM Interop Support
  3. *
  4. *
  5. * (C) 2002 Ximian, Inc. http://www.ximian.com
  6. *
  7. */
  8. #include "config.h"
  9. #ifdef HAVE_ALLOCA_H
  10. #include <alloca.h>
  11. #endif
  12. #include "object.h"
  13. #include "loader.h"
  14. #include "cil-coff.h"
  15. #include "metadata/cominterop.h"
  16. #include "metadata/marshal.h"
  17. #include "metadata/method-builder.h"
  18. #include "metadata/tabledefs.h"
  19. #include "metadata/exception.h"
  20. #include "metadata/appdomain.h"
  21. #include "mono/metadata/debug-helpers.h"
  22. #include "mono/metadata/threadpool.h"
  23. #include "mono/metadata/threads.h"
  24. #include "mono/metadata/monitor.h"
  25. #include "mono/metadata/metadata-internals.h"
  26. #include "mono/metadata/domain-internals.h"
  27. #include "mono/metadata/gc-internal.h"
  28. #include "mono/metadata/threads-types.h"
  29. #include "mono/metadata/string-icalls.h"
  30. #include "mono/metadata/attrdefs.h"
  31. #include "mono/metadata/gc-internal.h"
  32. #include "mono/utils/mono-counters.h"
  33. #include <string.h>
  34. #include <errno.h>
  35. /*
  36. Code shared between the DISABLE_COM and !DISABLE_COM
  37. */
  38. static void
  39. register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
  40. {
  41. MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
  42. mono_register_jit_icall (func, name, sig, save);
  43. }
  44. #ifndef DISABLE_COM
  45. #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
  46. a = i,
  47. typedef enum {
  48. MONO_MARSHAL_NONE, /* No marshalling needed */
  49. MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
  50. MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
  51. MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
  52. } MonoXDomainMarshalType;
  53. typedef enum {
  54. MONO_COM_DEFAULT,
  55. MONO_COM_MS
  56. } MonoCOMProvider;
  57. static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
  58. enum {
  59. #include "mono/cil/opcode.def"
  60. LAST = 0xff
  61. };
  62. #undef OPDEF
  63. /* This mutex protects the various cominterop related caches in MonoImage */
  64. #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
  65. #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
  66. static CRITICAL_SECTION cominterop_mutex;
  67. /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
  68. #ifdef HOST_WIN32
  69. #define STDCALL __stdcall
  70. #else
  71. #define STDCALL
  72. #endif
  73. /* Upon creation of a CCW, only allocate a weak handle and set the
  74. * reference count to 0. If the unmanaged client code decides to addref and
  75. * hold onto the CCW, I then allocate a strong handle. Once the reference count
  76. * goes back to 0, convert back to a weak handle.
  77. */
  78. typedef struct {
  79. guint32 ref_count;
  80. guint32 gc_handle;
  81. GHashTable* vtable_hash;
  82. #ifdef HOST_WIN32
  83. gpointer free_marshaler;
  84. #endif
  85. } MonoCCW;
  86. /* This type is the actual pointer passed to unmanaged code
  87. * to represent a COM interface.
  88. */
  89. typedef struct {
  90. gpointer vtable;
  91. MonoCCW* ccw;
  92. } MonoCCWInterface;
  93. /* IUnknown */
  94. static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
  95. static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
  96. static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
  97. /* IDispatch */
  98. static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
  99. static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
  100. static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
  101. gunichar2** rgszNames, guint32 cNames,
  102. guint32 lcid, gint32 *rgDispId);
  103. static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
  104. gpointer riid, guint32 lcid,
  105. guint16 wFlags, gpointer pDispParams,
  106. gpointer pVarResult, gpointer pExcepInfo,
  107. guint32 *puArgErr);
  108. static MonoMethod *
  109. cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
  110. static gpointer
  111. cominterop_get_ccw (MonoObject* object, MonoClass* itf);
  112. static MonoObject*
  113. cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
  114. /* SAFEARRAY marshalling */
  115. static gboolean
  116. mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
  117. static gpointer
  118. mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
  119. static gboolean
  120. mono_marshal_safearray_next (gpointer safearray, gpointer indices);
  121. static void
  122. mono_marshal_safearray_end (gpointer safearray, gpointer indices);
  123. static gboolean
  124. mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
  125. static void
  126. mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
  127. static void
  128. mono_marshal_safearray_free_indices (gpointer indices);
  129. /**
  130. * cominterop_method_signature:
  131. * @method: a method
  132. *
  133. * Returns: the corresponding unmanaged method signature for a managed COM
  134. * method.
  135. */
  136. static MonoMethodSignature*
  137. cominterop_method_signature (MonoMethod* method)
  138. {
  139. MonoMethodSignature *res;
  140. MonoImage *image = method->klass->image;
  141. MonoMethodSignature *sig = mono_method_signature (method);
  142. gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
  143. int sigsize;
  144. int i;
  145. int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
  146. if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
  147. param_count++;
  148. res = mono_metadata_signature_alloc (image, param_count);
  149. sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
  150. memcpy (res, sig, sigsize);
  151. // now move args forward one
  152. for (i = sig->param_count-1; i >= 0; i--)
  153. res->params[i+1] = sig->params[i];
  154. // first arg is interface pointer
  155. res->params[0] = &mono_defaults.int_class->byval_arg;
  156. if (preserve_sig) {
  157. res->ret = sig->ret;
  158. }
  159. else {
  160. // last arg is return type
  161. if (!MONO_TYPE_IS_VOID (sig->ret)) {
  162. res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
  163. res->params[param_count-1]->byref = 1;
  164. res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
  165. }
  166. // return type is always int32 (HRESULT)
  167. res->ret = &mono_defaults.int32_class->byval_arg;
  168. }
  169. // no pinvoke
  170. res->pinvoke = FALSE;
  171. // no hasthis
  172. res->hasthis = 0;
  173. // set param_count
  174. res->param_count = param_count;
  175. // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
  176. #ifdef HOST_WIN32
  177. res->call_convention = MONO_CALL_STDCALL;
  178. #else
  179. res->call_convention = MONO_CALL_C;
  180. #endif
  181. return res;
  182. }
  183. /**
  184. * cominterop_get_function_pointer:
  185. * @itf: a pointer to the COM interface
  186. * @slot: the vtable slot of the method pointer to return
  187. *
  188. * Returns: the unmanaged vtable function pointer from the interface
  189. */
  190. static gpointer
  191. cominterop_get_function_pointer (gpointer itf, int slot)
  192. {
  193. gpointer func;
  194. func = *((*(gpointer**)itf)+slot);
  195. return func;
  196. }
  197. /**
  198. * cominterop_object_is_com_object:
  199. * @obj: a pointer to the object
  200. *
  201. * Returns: a value indicating if the object is a
  202. * Runtime Callable Wrapper (RCW) for a COM object
  203. */
  204. static gboolean
  205. cominterop_object_is_rcw (MonoObject *obj)
  206. {
  207. MonoClass *klass = NULL;
  208. MonoRealProxy* real_proxy = NULL;
  209. if (!obj)
  210. return FALSE;
  211. klass = mono_object_class (obj);
  212. if (!mono_class_is_transparent_proxy (klass))
  213. return FALSE;
  214. real_proxy = ((MonoTransparentProxy*)obj)->rp;
  215. if (!real_proxy)
  216. return FALSE;
  217. klass = mono_object_class (real_proxy);
  218. return (klass && klass == mono_defaults.com_interop_proxy_class);
  219. }
  220. static int
  221. cominterop_get_com_slot_begin (MonoClass* klass)
  222. {
  223. static MonoClass *interface_type_attribute = NULL;
  224. MonoCustomAttrInfo *cinfo = NULL;
  225. MonoInterfaceTypeAttribute* itf_attr = NULL;
  226. if (!interface_type_attribute)
  227. interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
  228. cinfo = mono_custom_attrs_from_class (klass);
  229. if (cinfo) {
  230. itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
  231. if (!cinfo->cached)
  232. mono_custom_attrs_free (cinfo);
  233. }
  234. if (itf_attr && itf_attr->intType == 1)
  235. return 3; /* 3 methods in IUnknown*/
  236. else
  237. return 7; /* 7 methods in IDispatch*/
  238. }
  239. /**
  240. * cominterop_get_method_interface:
  241. * @method: method being called
  242. *
  243. * Returns: the MonoClass* representing the interface on which
  244. * the method is defined.
  245. */
  246. static MonoClass*
  247. cominterop_get_method_interface (MonoMethod* method)
  248. {
  249. MonoError error;
  250. MonoClass *ic = method->klass;
  251. /* if method is on a class, we need to look up interface method exists on */
  252. if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
  253. GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
  254. g_assert (mono_error_ok (&error));
  255. if (ifaces) {
  256. int i;
  257. mono_class_setup_vtable (method->klass);
  258. for (i = 0; i < ifaces->len; ++i) {
  259. int j, offset;
  260. gboolean found = FALSE;
  261. ic = g_ptr_array_index (ifaces, i);
  262. offset = mono_class_interface_offset (method->klass, ic);
  263. for (j = 0; j < ic->method.count; ++j) {
  264. if (method->klass->vtable [j + offset] == method) {
  265. found = TRUE;
  266. break;
  267. }
  268. }
  269. if (found)
  270. break;
  271. ic = NULL;
  272. }
  273. g_ptr_array_free (ifaces, TRUE);
  274. }
  275. }
  276. if (!ic)
  277. g_assert (ic);
  278. g_assert (MONO_CLASS_IS_INTERFACE (ic));
  279. return ic;
  280. }
  281. /**
  282. * cominterop_get_com_slot_for_method:
  283. * @method: a method
  284. *
  285. * Returns: the method's slot in the COM interface vtable
  286. */
  287. static int
  288. cominterop_get_com_slot_for_method (MonoMethod* method)
  289. {
  290. guint32 slot = method->slot;
  291. MonoClass *ic = method->klass;
  292. /* if method is on a class, we need to look up interface method exists on */
  293. if (!MONO_CLASS_IS_INTERFACE(ic)) {
  294. int offset = 0;
  295. int i = 0;
  296. ic = cominterop_get_method_interface (method);
  297. offset = mono_class_interface_offset (method->klass, ic);
  298. g_assert(offset >= 0);
  299. for(i = 0; i < ic->method.count; ++i) {
  300. if (method->klass->vtable [i + offset] == method)
  301. {
  302. slot = ic->methods[i]->slot;
  303. break;
  304. }
  305. }
  306. }
  307. g_assert (ic);
  308. g_assert (MONO_CLASS_IS_INTERFACE (ic));
  309. return slot + cominterop_get_com_slot_begin (ic);
  310. }
  311. static void
  312. cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
  313. static gboolean
  314. cominterop_class_guid (MonoClass* klass, guint8* guid)
  315. {
  316. static MonoClass *GuidAttribute = NULL;
  317. MonoCustomAttrInfo *cinfo;
  318. /* Handle the GuidAttribute */
  319. if (!GuidAttribute)
  320. GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
  321. cinfo = mono_custom_attrs_from_class (klass);
  322. if (cinfo) {
  323. MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
  324. if (!attr)
  325. return FALSE;
  326. if (!cinfo->cached)
  327. mono_custom_attrs_free (cinfo);
  328. cominterop_mono_string_to_guid (attr->guid, guid);
  329. return TRUE;
  330. }
  331. return FALSE;
  332. }
  333. static gboolean
  334. cominterop_com_visible (MonoClass* klass)
  335. {
  336. static MonoClass *ComVisibleAttribute = NULL;
  337. MonoError error;
  338. MonoCustomAttrInfo *cinfo;
  339. GPtrArray *ifaces;
  340. MonoBoolean visible = 1;
  341. /* Handle the ComVisibleAttribute */
  342. if (!ComVisibleAttribute)
  343. ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
  344. cinfo = mono_custom_attrs_from_class (klass);
  345. if (cinfo) {
  346. MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
  347. if (attr)
  348. visible = attr->visible;
  349. if (!cinfo->cached)
  350. mono_custom_attrs_free (cinfo);
  351. if (visible)
  352. return TRUE;
  353. }
  354. ifaces = mono_class_get_implemented_interfaces (klass, &error);
  355. g_assert (mono_error_ok (&error));
  356. if (ifaces) {
  357. int i;
  358. for (i = 0; i < ifaces->len; ++i) {
  359. MonoClass *ic = NULL;
  360. ic = g_ptr_array_index (ifaces, i);
  361. if (MONO_CLASS_IS_IMPORT (ic))
  362. visible = TRUE;
  363. }
  364. g_ptr_array_free (ifaces, TRUE);
  365. }
  366. return visible;
  367. }
  368. static void cominterop_raise_hr_exception (int hr)
  369. {
  370. static MonoMethod* throw_exception_for_hr = NULL;
  371. MonoException* ex;
  372. void* params[1] = {&hr};
  373. if (!throw_exception_for_hr)
  374. throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
  375. ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
  376. mono_raise_exception (ex);
  377. }
  378. /**
  379. * cominterop_get_interface:
  380. * @obj: managed wrapper object containing COM object
  381. * @ic: interface type to retrieve for COM object
  382. *
  383. * Returns: the COM interface requested
  384. */
  385. static gpointer
  386. cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
  387. {
  388. gpointer itf = NULL;
  389. g_assert (ic);
  390. g_assert (MONO_CLASS_IS_INTERFACE (ic));
  391. mono_cominterop_lock ();
  392. if (obj->itf_hash)
  393. itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
  394. mono_cominterop_unlock ();
  395. if (!itf) {
  396. guint8 iid [16];
  397. int found = cominterop_class_guid (ic, iid);
  398. int hr;
  399. g_assert(found);
  400. hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
  401. if (hr < 0 && throw_exception) {
  402. cominterop_raise_hr_exception (hr);
  403. }
  404. if (hr >= 0 && itf) {
  405. mono_cominterop_lock ();
  406. if (!obj->itf_hash)
  407. obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  408. g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
  409. mono_cominterop_unlock ();
  410. }
  411. }
  412. if (throw_exception)
  413. g_assert (itf);
  414. return itf;
  415. }
  416. static int
  417. cominterop_get_hresult_for_exception (MonoException* exc)
  418. {
  419. int hr = 0;
  420. return hr;
  421. }
  422. static MonoReflectionType *
  423. cominterop_type_from_handle (MonoType *handle)
  424. {
  425. MonoDomain *domain = mono_domain_get ();
  426. MonoClass *klass = mono_class_from_mono_type (handle);
  427. MONO_ARCH_SAVE_REGS;
  428. mono_class_init (klass);
  429. return mono_type_get_object (domain, handle);
  430. }
  431. void
  432. mono_cominterop_init (void)
  433. {
  434. char* com_provider_env = NULL;
  435. InitializeCriticalSection (&cominterop_mutex);
  436. com_provider_env = getenv ("MONO_COM");
  437. if (com_provider_env && !strcmp(com_provider_env, "MS"))
  438. com_provider = MONO_COM_MS;
  439. register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
  440. register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
  441. register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
  442. register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
  443. register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
  444. register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
  445. register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
  446. register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
  447. register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
  448. register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
  449. register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
  450. /* SAFEARRAY marshalling */
  451. register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
  452. register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
  453. register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
  454. register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
  455. register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
  456. register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
  457. register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
  458. }
  459. void
  460. mono_cominterop_cleanup (void)
  461. {
  462. DeleteCriticalSection (&cominterop_mutex);
  463. }
  464. void
  465. mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
  466. {
  467. // get function pointer from 1st arg, the COM interface pointer
  468. mono_mb_emit_ldarg (mb, 0);
  469. mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
  470. mono_mb_emit_icall (mb, cominterop_get_function_pointer);
  471. mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
  472. mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
  473. mono_mb_emit_calli (mb, sig);
  474. mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
  475. mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
  476. }
  477. void
  478. mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
  479. {
  480. switch (conv) {
  481. case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
  482. case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
  483. case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
  484. static MonoClass* com_interop_proxy_class = NULL;
  485. static MonoMethod* com_interop_proxy_get_proxy = NULL;
  486. static MonoMethod* get_transparent_proxy = NULL;
  487. int real_proxy;
  488. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  489. MonoClass *klass = NULL;
  490. /* COM types are initialized lazily */
  491. mono_init_com_types ();
  492. klass = mono_class_from_mono_type (type);
  493. mono_mb_emit_ldloc (mb, 1);
  494. mono_mb_emit_byte (mb, CEE_LDNULL);
  495. mono_mb_emit_byte (mb, CEE_STIND_REF);
  496. mono_mb_emit_ldloc (mb, 0);
  497. mono_mb_emit_byte (mb, CEE_LDIND_I);
  498. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  499. /* load dst to store later */
  500. mono_mb_emit_ldloc (mb, 1);
  501. mono_mb_emit_ldloc (mb, 0);
  502. mono_mb_emit_byte (mb, CEE_LDIND_I);
  503. mono_mb_emit_icon (mb, TRUE);
  504. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  505. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  506. if (!com_interop_proxy_class)
  507. com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
  508. if (!com_interop_proxy_get_proxy)
  509. com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
  510. #ifndef DISABLE_REMOTING
  511. if (!get_transparent_proxy)
  512. get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
  513. #endif
  514. real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
  515. mono_mb_emit_ldloc (mb, 0);
  516. mono_mb_emit_byte (mb, CEE_LDIND_I);
  517. mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
  518. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  519. mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
  520. mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
  521. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  522. g_assert (klass);
  523. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  524. }
  525. mono_mb_emit_byte (mb, CEE_STIND_REF);
  526. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  527. /* is already managed object */
  528. mono_mb_patch_short_branch (mb, pos_ccw);
  529. mono_mb_emit_ldloc (mb, 0);
  530. mono_mb_emit_byte (mb, CEE_LDIND_I);
  531. mono_mb_emit_icon (mb, TRUE);
  532. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  533. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  534. g_assert (klass);
  535. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  536. }
  537. mono_mb_emit_byte (mb, CEE_STIND_REF);
  538. mono_mb_patch_short_branch (mb, pos_end);
  539. /* case if null */
  540. mono_mb_patch_short_branch (mb, pos_null);
  541. break;
  542. }
  543. default:
  544. g_assert_not_reached ();
  545. }
  546. }
  547. void
  548. mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
  549. {
  550. switch (conv) {
  551. case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
  552. case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
  553. case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
  554. guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
  555. /* COM types are initialized lazily */
  556. mono_init_com_types ();
  557. mono_mb_emit_ldloc (mb, 1);
  558. mono_mb_emit_icon (mb, 0);
  559. mono_mb_emit_byte (mb, CEE_CONV_U);
  560. mono_mb_emit_byte (mb, CEE_STIND_I);
  561. mono_mb_emit_ldloc (mb, 0);
  562. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  563. // if null just break, dst was already inited to 0
  564. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  565. mono_mb_emit_ldloc (mb, 0);
  566. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  567. mono_mb_emit_icall (mb, cominterop_object_is_rcw);
  568. pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  569. // load dst to store later
  570. mono_mb_emit_ldloc (mb, 1);
  571. // load src
  572. mono_mb_emit_ldloc (mb, 0);
  573. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  574. mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
  575. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  576. /* load the RCW from the ComInteropProxy*/
  577. mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
  578. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  579. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
  580. mono_mb_emit_ptr (mb, mono_type_get_class (type));
  581. mono_mb_emit_icon (mb, TRUE);
  582. mono_mb_emit_icall (mb, cominterop_get_interface);
  583. }
  584. else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
  585. static MonoProperty* iunknown = NULL;
  586. if (!iunknown)
  587. iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
  588. mono_mb_emit_managed_call (mb, iunknown->get, NULL);
  589. }
  590. else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
  591. static MonoProperty* idispatch = NULL;
  592. if (!idispatch)
  593. idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
  594. mono_mb_emit_managed_call (mb, idispatch->get, NULL);
  595. }
  596. else {
  597. g_assert_not_reached ();
  598. }
  599. mono_mb_emit_byte (mb, CEE_STIND_I);
  600. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  601. // if not rcw
  602. mono_mb_patch_short_branch (mb, pos_rcw);
  603. /* load dst to store later */
  604. mono_mb_emit_ldloc (mb, 1);
  605. /* load src */
  606. mono_mb_emit_ldloc (mb, 0);
  607. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  608. if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
  609. mono_mb_emit_ptr (mb, mono_type_get_class (type));
  610. else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
  611. mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
  612. else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
  613. mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
  614. else
  615. g_assert_not_reached ();
  616. mono_mb_emit_icall (mb, cominterop_get_ccw);
  617. mono_mb_emit_byte (mb, CEE_STIND_I);
  618. mono_mb_patch_short_branch (mb, pos_end);
  619. mono_mb_patch_short_branch (mb, pos_null);
  620. break;
  621. }
  622. default:
  623. g_assert_not_reached ();
  624. }
  625. }
  626. /**
  627. * cominterop_get_native_wrapper_adjusted:
  628. * @method: managed COM Interop method
  629. *
  630. * Returns: the generated method to call with signature matching
  631. * the unmanaged COM Method signature
  632. */
  633. static MonoMethod *
  634. cominterop_get_native_wrapper_adjusted (MonoMethod *method)
  635. {
  636. MonoMethod *res;
  637. MonoMethodBuilder *mb_native;
  638. MonoMarshalSpec **mspecs;
  639. MonoMethodSignature *sig, *sig_native;
  640. MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
  641. int i;
  642. sig = mono_method_signature (method);
  643. // create unmanaged wrapper
  644. mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
  645. sig_native = cominterop_method_signature (method);
  646. mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
  647. memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
  648. mono_method_get_marshal_info (method, mspecs);
  649. // move managed args up one
  650. for (i = sig->param_count; i >= 1; i--)
  651. mspecs[i+1] = mspecs[i];
  652. // first arg is IntPtr for interface
  653. mspecs[1] = NULL;
  654. if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
  655. // move return spec to last param
  656. if (!MONO_TYPE_IS_VOID (sig->ret))
  657. mspecs[sig_native->param_count] = mspecs[0];
  658. mspecs[0] = NULL;
  659. }
  660. for (i = 1; i < sig_native->param_count; i++) {
  661. int mspec_index = i + 1;
  662. if (mspecs[mspec_index] == NULL) {
  663. // default object to VARIANT
  664. if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
  665. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  666. mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
  667. }
  668. else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
  669. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  670. mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
  671. }
  672. else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
  673. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  674. mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
  675. }
  676. else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
  677. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  678. mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
  679. }
  680. }
  681. }
  682. if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
  683. // move return spec to last param
  684. if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
  685. // default object to VARIANT
  686. if (sig->ret->type == MONO_TYPE_OBJECT) {
  687. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  688. mspecs[0]->native = MONO_NATIVE_STRUCT;
  689. }
  690. else if (sig->ret->type == MONO_TYPE_STRING) {
  691. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  692. mspecs[0]->native = MONO_NATIVE_BSTR;
  693. }
  694. else if (sig->ret->type == MONO_TYPE_CLASS) {
  695. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  696. mspecs[0]->native = MONO_NATIVE_INTERFACE;
  697. }
  698. else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
  699. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  700. mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
  701. }
  702. }
  703. }
  704. mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
  705. res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
  706. mono_mb_free (mb_native);
  707. for (i = sig_native->param_count; i >= 0; i--)
  708. if (mspecs [i])
  709. mono_metadata_free_marshal_spec (mspecs [i]);
  710. g_free (mspecs);
  711. return res;
  712. }
  713. /**
  714. * mono_cominterop_get_native_wrapper:
  715. * @method: managed method
  716. *
  717. * Returns: the generated method to call
  718. */
  719. MonoMethod *
  720. mono_cominterop_get_native_wrapper (MonoMethod *method)
  721. {
  722. MonoMethod *res;
  723. GHashTable *cache;
  724. MonoMethodBuilder *mb;
  725. MonoMethodSignature *sig, *csig;
  726. g_assert (method);
  727. cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
  728. if ((res = mono_marshal_find_in_cache (cache, method)))
  729. return res;
  730. mono_init_com_types ();
  731. if (!method->klass->vtable)
  732. mono_class_setup_vtable (method->klass);
  733. if (!method->klass->methods)
  734. mono_class_setup_methods (method->klass);
  735. g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
  736. sig = mono_method_signature (method);
  737. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
  738. /* if method klass is import, that means method
  739. * is really a com call. let interop system emit it.
  740. */
  741. if (MONO_CLASS_IS_IMPORT(method->klass)) {
  742. /* FIXME: we have to call actual class .ctor
  743. * instead of just __ComObject .ctor.
  744. */
  745. if (!strcmp(method->name, ".ctor")) {
  746. static MonoMethod *ctor = NULL;
  747. if (!ctor)
  748. ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
  749. mono_mb_emit_ldarg (mb, 0);
  750. mono_mb_emit_managed_call (mb, ctor, NULL);
  751. mono_mb_emit_byte (mb, CEE_RET);
  752. }
  753. else {
  754. static MonoMethod * ThrowExceptionForHR = NULL;
  755. MonoMethod *adjusted_method;
  756. int retval = 0;
  757. int ptr_this;
  758. int i;
  759. gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
  760. // add local variables
  761. ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  762. if (!MONO_TYPE_IS_VOID (sig->ret))
  763. retval = mono_mb_add_local (mb, sig->ret);
  764. // get the type for the interface the method is defined on
  765. // and then get the underlying COM interface for that type
  766. mono_mb_emit_ldarg (mb, 0);
  767. mono_mb_emit_ptr (mb, method);
  768. mono_mb_emit_icall (mb, cominterop_get_method_interface);
  769. mono_mb_emit_icon (mb, TRUE);
  770. mono_mb_emit_icall (mb, cominterop_get_interface);
  771. mono_mb_emit_stloc (mb, ptr_this);
  772. // arg 1 is unmanaged this pointer
  773. mono_mb_emit_ldloc (mb, ptr_this);
  774. // load args
  775. for (i = 1; i <= sig->param_count; i++)
  776. mono_mb_emit_ldarg (mb, i);
  777. // push managed return value as byref last argument
  778. if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
  779. mono_mb_emit_ldloc_addr (mb, retval);
  780. adjusted_method = cominterop_get_native_wrapper_adjusted (method);
  781. mono_mb_emit_managed_call (mb, adjusted_method, NULL);
  782. if (!preserve_sig) {
  783. if (!ThrowExceptionForHR)
  784. ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
  785. mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
  786. // load return value managed is expecting
  787. if (!MONO_TYPE_IS_VOID (sig->ret))
  788. mono_mb_emit_ldloc (mb, retval);
  789. }
  790. mono_mb_emit_byte (mb, CEE_RET);
  791. }
  792. }
  793. /* Does this case ever get hit? */
  794. else {
  795. char *msg = g_strdup ("non imported interfaces on \
  796. imported classes is not yet implemented.");
  797. mono_mb_emit_exception (mb, "NotSupportedException", msg);
  798. }
  799. csig = mono_metadata_signature_dup_full (method->klass->image, sig);
  800. csig->pinvoke = 0;
  801. res = mono_mb_create_and_cache (cache, method,
  802. mb, csig, csig->param_count + 16);
  803. mono_mb_free (mb);
  804. return res;
  805. }
  806. /**
  807. * mono_cominterop_get_invoke:
  808. * @method: managed method
  809. *
  810. * Returns: the generated method that calls the underlying __ComObject
  811. * rather than the proxy object.
  812. */
  813. MonoMethod *
  814. mono_cominterop_get_invoke (MonoMethod *method)
  815. {
  816. MonoMethodSignature *sig;
  817. MonoMethodBuilder *mb;
  818. MonoMethod *res;
  819. int i, temp_obj;
  820. GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
  821. g_assert (method);
  822. if ((res = mono_marshal_find_in_cache (cache, method)))
  823. return res;
  824. sig = mono_signature_no_pinvoke (method);
  825. /* we cant remote methods without this pointer */
  826. if (!sig->hasthis)
  827. return method;
  828. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
  829. /* get real proxy object, which is a ComInteropProxy in this case*/
  830. temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  831. mono_mb_emit_ldarg (mb, 0);
  832. mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
  833. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  834. /* load the RCW from the ComInteropProxy*/
  835. mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
  836. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  837. /* load args and make the call on the RCW */
  838. for (i = 1; i <= sig->param_count; i++)
  839. mono_mb_emit_ldarg (mb, i);
  840. if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
  841. MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
  842. mono_mb_emit_managed_call (mb, native_wrapper, NULL);
  843. }
  844. else {
  845. if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
  846. mono_mb_emit_op (mb, CEE_CALLVIRT, method);
  847. else
  848. mono_mb_emit_op (mb, CEE_CALL, method);
  849. }
  850. if (!strcmp(method->name, ".ctor")) {
  851. static MonoClass *com_interop_proxy_class = NULL;
  852. static MonoMethod *cache_proxy = NULL;
  853. if (!com_interop_proxy_class)
  854. com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
  855. if (!cache_proxy)
  856. cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
  857. mono_mb_emit_ldarg (mb, 0);
  858. mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
  859. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  860. mono_mb_emit_managed_call (mb, cache_proxy, NULL);
  861. }
  862. mono_marshal_emit_thread_interrupt_checkpoint (mb);
  863. mono_mb_emit_byte (mb, CEE_RET);
  864. res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
  865. mono_mb_free (mb);
  866. return res;
  867. }
  868. /* Maps a managed object to its unmanaged representation
  869. * i.e. it's COM Callable Wrapper (CCW).
  870. * Key: MonoObject*
  871. * Value: MonoCCW*
  872. */
  873. static GHashTable* ccw_hash = NULL;
  874. /* Maps a CCW interface to it's containing CCW.
  875. * Note that a CCW support many interfaces.
  876. * Key: MonoCCW*
  877. * Value: MonoCCWInterface*
  878. */
  879. static GHashTable* ccw_interface_hash = NULL;
  880. /* Maps the IUnknown value of a RCW to
  881. * it's MonoComInteropProxy*.
  882. * Key: void*
  883. * Value: gchandle
  884. */
  885. static GHashTable* rcw_hash = NULL;
  886. int
  887. mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
  888. MonoType *t,
  889. MonoMarshalSpec *spec,
  890. int conv_arg, MonoType **conv_arg_type,
  891. MarshalAction action)
  892. {
  893. MonoMethodBuilder *mb = m->mb;
  894. MonoClass *klass = t->data.klass;
  895. static MonoMethod* get_object_for_iunknown = NULL;
  896. static MonoMethod* get_iunknown_for_object_internal = NULL;
  897. static MonoMethod* get_com_interface_for_object_internal = NULL;
  898. static MonoMethod* get_idispatch_for_object_internal = NULL;
  899. static MonoMethod* marshal_release = NULL;
  900. static MonoMethod* AddRef = NULL;
  901. if (!get_object_for_iunknown)
  902. get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
  903. if (!get_iunknown_for_object_internal)
  904. get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
  905. if (!get_idispatch_for_object_internal)
  906. get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
  907. if (!get_com_interface_for_object_internal)
  908. get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
  909. if (!marshal_release)
  910. marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
  911. /* COM types are initialized lazily */
  912. mono_init_com_types ();
  913. switch (action) {
  914. case MARSHAL_ACTION_CONV_IN: {
  915. guint32 pos_null = 0;
  916. *conv_arg_type = &mono_defaults.int_class->byval_arg;
  917. conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  918. mono_mb_emit_ptr (mb, NULL);
  919. mono_mb_emit_stloc (mb, conv_arg);
  920. /* we dont need any conversions for out parameters */
  921. if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
  922. break;
  923. mono_mb_emit_ldarg (mb, argnum);
  924. if (t->byref)
  925. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  926. /* if null just break, conv arg was already inited to 0 */
  927. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  928. mono_mb_emit_ldarg (mb, argnum);
  929. if (t->byref)
  930. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  931. if (klass && klass != mono_defaults.object_class) {
  932. mono_mb_emit_ptr (mb, t);
  933. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  934. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  935. }
  936. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  937. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  938. else if (spec->native == MONO_NATIVE_IDISPATCH)
  939. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  940. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  941. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  942. else
  943. g_assert_not_reached ();
  944. mono_mb_emit_stloc (mb, conv_arg);
  945. mono_mb_patch_short_branch (mb, pos_null);
  946. break;
  947. }
  948. case MARSHAL_ACTION_CONV_OUT: {
  949. if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
  950. int ccw_obj;
  951. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  952. ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  953. mono_mb_emit_ldarg (mb, argnum);
  954. mono_mb_emit_byte (mb, CEE_LDNULL);
  955. mono_mb_emit_byte (mb, CEE_STIND_REF);
  956. mono_mb_emit_ldloc (mb, conv_arg);
  957. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  958. mono_mb_emit_ldloc (mb, conv_arg);
  959. mono_mb_emit_icon (mb, TRUE);
  960. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  961. mono_mb_emit_stloc (mb, ccw_obj);
  962. mono_mb_emit_ldloc (mb, ccw_obj);
  963. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  964. mono_mb_emit_ldarg (mb, argnum);
  965. mono_mb_emit_ldloc (mb, conv_arg);
  966. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  967. if (klass && klass != mono_defaults.object_class)
  968. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  969. mono_mb_emit_byte (mb, CEE_STIND_REF);
  970. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  971. /* is already managed object */
  972. mono_mb_patch_short_branch (mb, pos_ccw);
  973. mono_mb_emit_ldarg (mb, argnum);
  974. mono_mb_emit_ldloc (mb, ccw_obj);
  975. if (klass && klass != mono_defaults.object_class)
  976. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  977. mono_mb_emit_byte (mb, CEE_STIND_REF);
  978. mono_mb_patch_short_branch (mb, pos_end);
  979. /* need to call Release to follow COM rules of ownership */
  980. mono_mb_emit_ldloc (mb, conv_arg);
  981. mono_mb_emit_managed_call (mb, marshal_release, NULL);
  982. mono_mb_emit_byte (mb, CEE_POP);
  983. /* case if null */
  984. mono_mb_patch_short_branch (mb, pos_null);
  985. }
  986. break;
  987. }
  988. case MARSHAL_ACTION_PUSH:
  989. if (t->byref)
  990. mono_mb_emit_ldloc_addr (mb, conv_arg);
  991. else
  992. mono_mb_emit_ldloc (mb, conv_arg);
  993. break;
  994. case MARSHAL_ACTION_CONV_RESULT: {
  995. int ccw_obj, ret_ptr;
  996. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  997. ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  998. ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  999. /* store return value */
  1000. mono_mb_emit_stloc (mb, ret_ptr);
  1001. mono_mb_emit_ldloc (mb, ret_ptr);
  1002. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1003. mono_mb_emit_ldloc (mb, ret_ptr);
  1004. mono_mb_emit_icon (mb, TRUE);
  1005. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1006. mono_mb_emit_stloc (mb, ccw_obj);
  1007. mono_mb_emit_ldloc (mb, ccw_obj);
  1008. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  1009. mono_mb_emit_ldloc (mb, ret_ptr);
  1010. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  1011. if (klass && klass != mono_defaults.object_class)
  1012. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1013. mono_mb_emit_stloc (mb, 3);
  1014. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  1015. /* is already managed object */
  1016. mono_mb_patch_short_branch (mb, pos_ccw);
  1017. mono_mb_emit_ldloc (mb, ccw_obj);
  1018. if (klass && klass != mono_defaults.object_class)
  1019. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1020. mono_mb_emit_stloc (mb, 3);
  1021. mono_mb_patch_short_branch (mb, pos_end);
  1022. /* need to call Release to follow COM rules of ownership */
  1023. mono_mb_emit_ldloc (mb, ret_ptr);
  1024. mono_mb_emit_managed_call (mb, marshal_release, NULL);
  1025. mono_mb_emit_byte (mb, CEE_POP);
  1026. /* case if null */
  1027. mono_mb_patch_short_branch (mb, pos_null);
  1028. break;
  1029. }
  1030. case MARSHAL_ACTION_MANAGED_CONV_IN: {
  1031. int ccw_obj;
  1032. guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
  1033. ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  1034. klass = mono_class_from_mono_type (t);
  1035. conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
  1036. *conv_arg_type = &mono_defaults.int_class->byval_arg;
  1037. mono_mb_emit_byte (mb, CEE_LDNULL);
  1038. mono_mb_emit_stloc (mb, conv_arg);
  1039. if (t->attrs & PARAM_ATTRIBUTE_OUT)
  1040. break;
  1041. mono_mb_emit_ldarg (mb, argnum);
  1042. if (t->byref)
  1043. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1044. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1045. mono_mb_emit_ldarg (mb, argnum);
  1046. if (t->byref)
  1047. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1048. mono_mb_emit_icon (mb, TRUE);
  1049. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1050. mono_mb_emit_stloc (mb, ccw_obj);
  1051. mono_mb_emit_ldloc (mb, ccw_obj);
  1052. pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  1053. mono_mb_emit_ldarg (mb, argnum);
  1054. if (t->byref)
  1055. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  1056. mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
  1057. if (klass && klass != mono_defaults.object_class)
  1058. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1059. mono_mb_emit_stloc (mb, conv_arg);
  1060. pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
  1061. /* is already managed object */
  1062. mono_mb_patch_short_branch (mb, pos_ccw);
  1063. mono_mb_emit_ldloc (mb, ccw_obj);
  1064. if (klass && klass != mono_defaults.object_class)
  1065. mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
  1066. mono_mb_emit_stloc (mb, conv_arg);
  1067. mono_mb_patch_short_branch (mb, pos_end);
  1068. /* case if null */
  1069. mono_mb_patch_short_branch (mb, pos_null);
  1070. break;
  1071. }
  1072. case MARSHAL_ACTION_MANAGED_CONV_OUT: {
  1073. if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
  1074. guint32 pos_null = 0;
  1075. if (!AddRef)
  1076. AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
  1077. mono_mb_emit_ldarg (mb, argnum);
  1078. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  1079. mono_mb_emit_byte (mb, CEE_STIND_I);
  1080. mono_mb_emit_ldloc (mb, conv_arg);
  1081. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1082. /* to store later */
  1083. mono_mb_emit_ldarg (mb, argnum);
  1084. mono_mb_emit_ldloc (mb, conv_arg);
  1085. if (klass && klass != mono_defaults.object_class) {
  1086. mono_mb_emit_ptr (mb, t);
  1087. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  1088. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  1089. }
  1090. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  1091. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1092. else if (spec->native == MONO_NATIVE_IDISPATCH)
  1093. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  1094. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  1095. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1096. else
  1097. g_assert_not_reached ();
  1098. mono_mb_emit_byte (mb, CEE_STIND_I);
  1099. mono_mb_emit_ldarg (mb, argnum);
  1100. mono_mb_emit_byte (mb, CEE_LDIND_I);
  1101. mono_mb_emit_managed_call (mb, AddRef, NULL);
  1102. mono_mb_emit_byte (mb, CEE_POP);
  1103. mono_mb_patch_short_branch (mb, pos_null);
  1104. }
  1105. break;
  1106. }
  1107. case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
  1108. guint32 pos_null = 0;
  1109. int ccw_obj;
  1110. ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  1111. if (!AddRef)
  1112. AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
  1113. /* store return value */
  1114. mono_mb_emit_stloc (mb, ccw_obj);
  1115. mono_mb_emit_ldloc (mb, ccw_obj);
  1116. /* if null just break, conv arg was already inited to 0 */
  1117. pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  1118. /* to store later */
  1119. mono_mb_emit_ldloc (mb, ccw_obj);
  1120. if (klass && klass != mono_defaults.object_class) {
  1121. mono_mb_emit_ptr (mb, t);
  1122. mono_mb_emit_icall (mb, cominterop_type_from_handle);
  1123. mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
  1124. }
  1125. else if (spec->native == MONO_NATIVE_IUNKNOWN)
  1126. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1127. else if (spec->native == MONO_NATIVE_IDISPATCH)
  1128. mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
  1129. else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
  1130. mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
  1131. else
  1132. g_assert_not_reached ();
  1133. mono_mb_emit_stloc (mb, 3);
  1134. mono_mb_emit_ldloc (mb, 3);
  1135. mono_mb_emit_managed_call (mb, AddRef, NULL);
  1136. mono_mb_emit_byte (mb, CEE_POP);
  1137. mono_mb_patch_short_branch (mb, pos_null);
  1138. break;
  1139. }
  1140. default:
  1141. g_assert_not_reached ();
  1142. }
  1143. return conv_arg;
  1144. }
  1145. typedef struct
  1146. {
  1147. int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
  1148. int (STDCALL *AddRef)(gpointer pUnk);
  1149. int (STDCALL *Release)(gpointer pUnk);
  1150. } MonoIUnknown;
  1151. #define MONO_S_OK 0x00000000L
  1152. #define MONO_E_NOINTERFACE 0x80004002L
  1153. #define MONO_E_NOTIMPL 0x80004001L
  1154. int
  1155. ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
  1156. {
  1157. g_assert (pUnk);
  1158. return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
  1159. }
  1160. int
  1161. ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
  1162. {
  1163. g_assert (pUnk);
  1164. return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
  1165. }
  1166. int
  1167. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
  1168. {
  1169. g_assert (pUnk);
  1170. return (*(MonoIUnknown**)pUnk)->Release(pUnk);
  1171. }
  1172. static gboolean cominterop_can_support_dispatch (MonoClass* klass)
  1173. {
  1174. if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
  1175. return FALSE;
  1176. if (!cominterop_com_visible (klass))
  1177. return FALSE;
  1178. return TRUE;
  1179. }
  1180. static void*
  1181. cominterop_get_idispatch_for_object (MonoObject* object)
  1182. {
  1183. if (!object)
  1184. return NULL;
  1185. if (cominterop_object_is_rcw (object)) {
  1186. return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
  1187. mono_defaults.idispatch_class, TRUE);
  1188. }
  1189. else {
  1190. MonoClass* klass = mono_object_class (object);
  1191. if (!cominterop_can_support_dispatch (klass) )
  1192. cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
  1193. return cominterop_get_ccw (object, mono_defaults.idispatch_class);
  1194. }
  1195. }
  1196. void*
  1197. ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
  1198. {
  1199. #ifndef DISABLE_COM
  1200. if (!object)
  1201. return NULL;
  1202. mono_init_com_types ();
  1203. if (cominterop_object_is_rcw (object)) {
  1204. MonoClass *klass = NULL;
  1205. MonoRealProxy* real_proxy = NULL;
  1206. if (!object)
  1207. return NULL;
  1208. klass = mono_object_class (object);
  1209. if (!mono_class_is_transparent_proxy (klass)) {
  1210. g_assert_not_reached ();
  1211. return NULL;
  1212. }
  1213. real_proxy = ((MonoTransparentProxy*)object)->rp;
  1214. if (!real_proxy) {
  1215. g_assert_not_reached ();
  1216. return NULL;
  1217. }
  1218. klass = mono_object_class (real_proxy);
  1219. if (klass != mono_defaults.com_interop_proxy_class) {
  1220. g_assert_not_reached ();
  1221. return NULL;
  1222. }
  1223. if (!((MonoComInteropProxy*)real_proxy)->com_object) {
  1224. g_assert_not_reached ();
  1225. return NULL;
  1226. }
  1227. return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
  1228. }
  1229. else {
  1230. return cominterop_get_ccw (object, mono_defaults.iunknown_class);
  1231. }
  1232. #else
  1233. g_assert_not_reached ();
  1234. #endif
  1235. }
  1236. MonoObject*
  1237. ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
  1238. {
  1239. #ifndef DISABLE_COM
  1240. MonoObject* object = NULL;
  1241. if (!pUnk)
  1242. return NULL;
  1243. /* see if it is a CCW */
  1244. object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
  1245. return object;
  1246. #else
  1247. g_assert_not_reached ();
  1248. #endif
  1249. }
  1250. void*
  1251. ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
  1252. {
  1253. #ifndef DISABLE_COM
  1254. mono_init_com_types ();
  1255. return cominterop_get_idispatch_for_object (object);
  1256. #else
  1257. g_assert_not_reached ();
  1258. #endif
  1259. }
  1260. void*
  1261. ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
  1262. {
  1263. #ifndef DISABLE_COM
  1264. MonoClass* klass = NULL;
  1265. void* itf = NULL;
  1266. g_assert (type);
  1267. g_assert (type->type);
  1268. klass = mono_type_get_class (type->type);
  1269. g_assert (klass);
  1270. if (!mono_class_init (klass))
  1271. mono_raise_exception (mono_class_get_exception_for_failure (klass));
  1272. itf = cominterop_get_ccw (object, klass);
  1273. g_assert (itf);
  1274. return itf;
  1275. #else
  1276. g_assert_not_reached ();
  1277. #endif
  1278. }
  1279. MonoBoolean
  1280. ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
  1281. {
  1282. #ifndef DISABLE_COM
  1283. return (MonoBoolean)cominterop_object_is_rcw (object);
  1284. #else
  1285. g_assert_not_reached ();
  1286. #endif
  1287. }
  1288. gint32
  1289. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
  1290. {
  1291. #ifndef DISABLE_COM
  1292. MonoComInteropProxy* proxy = NULL;
  1293. gint32 ref_count = 0;
  1294. g_assert (object);
  1295. g_assert (cominterop_object_is_rcw (object));
  1296. proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
  1297. g_assert (proxy);
  1298. if (proxy->ref_count == 0)
  1299. return -1;
  1300. ref_count = InterlockedDecrement (&proxy->ref_count);
  1301. g_assert (ref_count >= 0);
  1302. if (ref_count == 0)
  1303. ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
  1304. return ref_count;
  1305. #else
  1306. g_assert_not_reached ();
  1307. #endif
  1308. }
  1309. guint32
  1310. ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
  1311. {
  1312. MONO_ARCH_SAVE_REGS;
  1313. #ifndef DISABLE_COM
  1314. return cominterop_get_com_slot_for_method (m->method);
  1315. #else
  1316. g_assert_not_reached ();
  1317. #endif
  1318. }
  1319. /* Only used for COM RCWs */
  1320. MonoObject *
  1321. ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
  1322. {
  1323. MonoClass *klass;
  1324. MonoDomain *domain;
  1325. MonoObject *obj;
  1326. MONO_ARCH_SAVE_REGS;
  1327. domain = mono_object_domain (type);
  1328. klass = mono_class_from_mono_type (type->type);
  1329. /* call mono_object_new_alloc_specific instead of mono_object_new
  1330. * because we want to actually create object. mono_object_new checks
  1331. * to see if type is import and creates transparent proxy. this method
  1332. * is called by the corresponding real proxy to create the real RCW.
  1333. * Constructor does not need to be called. Will be called later.
  1334. */
  1335. obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
  1336. return obj;
  1337. }
  1338. static gboolean
  1339. cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
  1340. {
  1341. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
  1342. return TRUE;
  1343. }
  1344. void
  1345. ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
  1346. {
  1347. g_assert(obj);
  1348. if (obj->itf_hash) {
  1349. guint32 gchandle = 0;
  1350. mono_cominterop_lock ();
  1351. gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
  1352. if (gchandle) {
  1353. mono_gchandle_free (gchandle);
  1354. g_hash_table_remove (rcw_hash, obj->iunknown);
  1355. }
  1356. g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
  1357. g_hash_table_destroy (obj->itf_hash);
  1358. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
  1359. obj->itf_hash = obj->iunknown = NULL;
  1360. mono_cominterop_unlock ();
  1361. }
  1362. }
  1363. static gboolean
  1364. cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
  1365. {
  1366. guint32 gchandle = 0;
  1367. gchandle = GPOINTER_TO_UINT (value);
  1368. if (gchandle) {
  1369. MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
  1370. if (proxy) {
  1371. if (proxy->com_object->itf_hash) {
  1372. g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
  1373. g_hash_table_destroy (proxy->com_object->itf_hash);
  1374. }
  1375. if (proxy->com_object->iunknown)
  1376. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
  1377. proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
  1378. }
  1379. mono_gchandle_free (gchandle);
  1380. }
  1381. return TRUE;
  1382. }
  1383. void
  1384. cominterop_release_all_rcws (void)
  1385. {
  1386. if (!rcw_hash)
  1387. return;
  1388. mono_cominterop_lock ();
  1389. g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
  1390. g_hash_table_destroy (rcw_hash);
  1391. rcw_hash = NULL;
  1392. mono_cominterop_unlock ();
  1393. }
  1394. gpointer
  1395. ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
  1396. {
  1397. #ifndef DISABLE_COM
  1398. MonoClass *class = mono_type_get_class (type->type);
  1399. if (!mono_class_init (class))
  1400. mono_raise_exception (mono_class_get_exception_for_failure (class));
  1401. return cominterop_get_interface (obj, class, (gboolean)throw_exception);
  1402. #else
  1403. g_assert_not_reached ();
  1404. #endif
  1405. }
  1406. void
  1407. ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
  1408. {
  1409. #ifndef DISABLE_COM
  1410. guint32 gchandle = 0;
  1411. if (!rcw_hash) {
  1412. mono_cominterop_lock ();
  1413. rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1414. mono_cominterop_unlock ();
  1415. }
  1416. gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
  1417. mono_cominterop_lock ();
  1418. g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
  1419. mono_cominterop_unlock ();
  1420. #else
  1421. g_assert_not_reached ();
  1422. #endif
  1423. }
  1424. MonoComInteropProxy*
  1425. ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
  1426. {
  1427. #ifndef DISABLE_COM
  1428. MonoComInteropProxy* proxy = NULL;
  1429. guint32 gchandle = 0;
  1430. mono_cominterop_lock ();
  1431. if (rcw_hash)
  1432. gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
  1433. mono_cominterop_unlock ();
  1434. if (gchandle) {
  1435. proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
  1436. /* proxy is null means we need to free up old RCW */
  1437. if (!proxy) {
  1438. mono_gchandle_free (gchandle);
  1439. g_hash_table_remove (rcw_hash, pUnk);
  1440. }
  1441. }
  1442. return proxy;
  1443. #else
  1444. g_assert_not_reached ();
  1445. #endif
  1446. }
  1447. /**
  1448. * cominterop_get_ccw_object:
  1449. * @ccw_entry: a pointer to the CCWEntry
  1450. * @verify: verify ccw_entry is in fact a ccw
  1451. *
  1452. * Returns: the corresponding object for the CCW
  1453. */
  1454. static MonoObject*
  1455. cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
  1456. {
  1457. MonoCCW *ccw = NULL;
  1458. /* no CCW's exist yet */
  1459. if (!ccw_interface_hash)
  1460. return NULL;
  1461. if (verify) {
  1462. ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
  1463. }
  1464. else {
  1465. ccw = ccw_entry->ccw;
  1466. g_assert (ccw);
  1467. }
  1468. if (ccw)
  1469. return mono_gchandle_get_target (ccw->gc_handle);
  1470. else
  1471. return NULL;
  1472. }
  1473. static void
  1474. cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
  1475. {
  1476. MonoMethodSignature *sig, *csig;
  1477. sig = mono_method_signature (method);
  1478. /* we copy the signature, so that we can modify it */
  1479. /* FIXME: which to use? */
  1480. csig = mono_metadata_signature_dup_full (method->klass->image, sig);
  1481. /* csig = mono_metadata_signature_dup (sig); */
  1482. /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
  1483. #ifdef HOST_WIN32
  1484. csig->call_convention = MONO_CALL_STDCALL;
  1485. #else
  1486. csig->call_convention = MONO_CALL_C;
  1487. #endif
  1488. csig->hasthis = 0;
  1489. csig->pinvoke = 1;
  1490. m->image = method->klass->image;
  1491. m->piinfo = NULL;
  1492. m->retobj_var = 0;
  1493. m->sig = sig;
  1494. m->csig = csig;
  1495. }
  1496. /**
  1497. * cominterop_get_ccw:
  1498. * @object: a pointer to the object
  1499. * @itf: interface type needed
  1500. *
  1501. * Returns: a value indicating if the object is a
  1502. * Runtime Callable Wrapper (RCW) for a COM object
  1503. */
  1504. static gpointer
  1505. cominterop_get_ccw (MonoObject* object, MonoClass* itf)
  1506. {
  1507. int i;
  1508. MonoCCW *ccw = NULL;
  1509. MonoCCWInterface* ccw_entry = NULL;
  1510. gpointer *vtable = NULL;
  1511. static gpointer iunknown[3] = {NULL, NULL, NULL};
  1512. static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
  1513. MonoClass* iface = NULL;
  1514. MonoClass* klass = NULL;
  1515. EmitMarshalContext m;
  1516. int start_slot = 3;
  1517. int method_count = 0;
  1518. GList *ccw_list, *ccw_list_item;
  1519. MonoCustomAttrInfo *cinfo = NULL;
  1520. if (!object)
  1521. return NULL;
  1522. klass = mono_object_get_class (object);
  1523. mono_cominterop_lock ();
  1524. if (!ccw_hash)
  1525. ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1526. if (!ccw_interface_hash)
  1527. ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1528. ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
  1529. mono_cominterop_unlock ();
  1530. ccw_list_item = ccw_list;
  1531. while (ccw_list_item) {
  1532. MonoCCW* ccw_iter = ccw_list_item->data;
  1533. if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
  1534. ccw = ccw_iter;
  1535. break;
  1536. }
  1537. ccw_list_item = g_list_next(ccw_list_item);
  1538. }
  1539. if (!iunknown [0]) {
  1540. iunknown [0] = cominterop_ccw_queryinterface;
  1541. iunknown [1] = cominterop_ccw_addref;
  1542. iunknown [2] = cominterop_ccw_release;
  1543. }
  1544. if (!idispatch [0]) {
  1545. idispatch [0] = cominterop_ccw_get_type_info_count;
  1546. idispatch [1] = cominterop_ccw_get_type_info;
  1547. idispatch [2] = cominterop_ccw_get_ids_of_names;
  1548. idispatch [3] = cominterop_ccw_invoke;
  1549. }
  1550. if (!ccw) {
  1551. ccw = g_new0 (MonoCCW, 1);
  1552. #ifdef HOST_WIN32
  1553. ccw->free_marshaler = 0;
  1554. #endif
  1555. ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
  1556. ccw->ref_count = 0;
  1557. /* just alloc a weak handle until we are addref'd*/
  1558. ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
  1559. if (!ccw_list) {
  1560. ccw_list = g_list_alloc ();
  1561. ccw_list->data = ccw;
  1562. }
  1563. else
  1564. ccw_list = g_list_append (ccw_list, ccw);
  1565. mono_cominterop_lock ();
  1566. g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
  1567. mono_cominterop_unlock ();
  1568. /* register for finalization to clean up ccw */
  1569. mono_object_register_finalizer (object);
  1570. }
  1571. cinfo = mono_custom_attrs_from_class (itf);
  1572. if (cinfo) {
  1573. static MonoClass* coclass_attribute = NULL;
  1574. if (!coclass_attribute)
  1575. coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
  1576. if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
  1577. g_assert(itf->interface_count && itf->interfaces[0]);
  1578. itf = itf->interfaces[0];
  1579. }
  1580. if (!cinfo->cached)
  1581. mono_custom_attrs_free (cinfo);
  1582. }
  1583. iface = itf;
  1584. if (iface == mono_defaults.iunknown_class) {
  1585. start_slot = 3;
  1586. }
  1587. else if (iface == mono_defaults.idispatch_class) {
  1588. start_slot = 7;
  1589. }
  1590. else {
  1591. method_count += iface->method.count;
  1592. start_slot = cominterop_get_com_slot_begin (iface);
  1593. iface = NULL;
  1594. }
  1595. ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
  1596. if (!ccw_entry) {
  1597. int vtable_index = method_count-1+start_slot;
  1598. vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
  1599. memcpy (vtable, iunknown, sizeof (iunknown));
  1600. if (start_slot == 7)
  1601. memcpy (vtable+3, idispatch, sizeof (idispatch));
  1602. iface = itf;
  1603. for (i = iface->method.count-1; i >= 0;i--) {
  1604. int param_index = 0;
  1605. MonoMethodBuilder *mb;
  1606. MonoMarshalSpec ** mspecs;
  1607. MonoMethod *wrapper_method, *adjust_method;
  1608. MonoMethod *method = iface->methods [i];
  1609. MonoMethodSignature* sig_adjusted;
  1610. MonoMethodSignature* sig = mono_method_signature (method);
  1611. gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
  1612. mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
  1613. adjust_method = cominterop_get_managed_wrapper_adjusted (method);
  1614. sig_adjusted = mono_method_signature (adjust_method);
  1615. mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
  1616. mono_method_get_marshal_info (method, mspecs);
  1617. /* move managed args up one */
  1618. for (param_index = sig->param_count; param_index >= 1; param_index--) {
  1619. int mspec_index = param_index+1;
  1620. mspecs [mspec_index] = mspecs [param_index];
  1621. if (mspecs[mspec_index] == NULL) {
  1622. if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
  1623. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  1624. mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
  1625. }
  1626. else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
  1627. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  1628. mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
  1629. }
  1630. else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
  1631. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  1632. mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
  1633. }
  1634. else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
  1635. mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
  1636. mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
  1637. }
  1638. } else {
  1639. /* increase SizeParamIndex since we've added a param */
  1640. if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
  1641. sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
  1642. if (mspecs[mspec_index]->data.array_data.param_num != -1)
  1643. mspecs[mspec_index]->data.array_data.param_num++;
  1644. }
  1645. }
  1646. /* first arg is IntPtr for interface */
  1647. mspecs [1] = NULL;
  1648. /* move return spec to last param */
  1649. if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
  1650. if (mspecs [0] == NULL) {
  1651. if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
  1652. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  1653. mspecs[0]->native = MONO_NATIVE_STRUCT;
  1654. }
  1655. else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
  1656. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  1657. mspecs[0]->native = MONO_NATIVE_BSTR;
  1658. }
  1659. else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
  1660. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  1661. mspecs[0]->native = MONO_NATIVE_INTERFACE;
  1662. }
  1663. else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
  1664. mspecs[0] = g_new0 (MonoMarshalSpec, 1);
  1665. mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
  1666. }
  1667. }
  1668. mspecs [sig_adjusted->param_count] = mspecs [0];
  1669. mspecs [0] = NULL;
  1670. }
  1671. /* skip visiblity since we call internal methods */
  1672. mb->skip_visibility = TRUE;
  1673. cominterop_setup_marshal_context (&m, adjust_method);
  1674. m.mb = mb;
  1675. mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
  1676. mono_loader_lock ();
  1677. mono_cominterop_lock ();
  1678. wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
  1679. mono_cominterop_unlock ();
  1680. mono_loader_unlock ();
  1681. vtable [vtable_index--] = mono_compile_method (wrapper_method);
  1682. for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
  1683. if (mspecs [param_index])
  1684. mono_metadata_free_marshal_spec (mspecs [param_index]);
  1685. g_free (mspecs);
  1686. }
  1687. ccw_entry = g_new0 (MonoCCWInterface, 1);
  1688. ccw_entry->ccw = ccw;
  1689. ccw_entry->vtable = vtable;
  1690. g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
  1691. g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
  1692. }
  1693. return ccw_entry;
  1694. }
  1695. static gboolean
  1696. mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
  1697. {
  1698. g_hash_table_remove (ccw_interface_hash, value);
  1699. g_assert (value);
  1700. g_free (value);
  1701. return TRUE;
  1702. }
  1703. /**
  1704. * mono_marshal_free_ccw:
  1705. * @object: the mono object
  1706. *
  1707. * Returns: whether the object had a CCW
  1708. */
  1709. gboolean
  1710. mono_marshal_free_ccw (MonoObject* object)
  1711. {
  1712. GList *ccw_list, *ccw_list_orig, *ccw_list_item;
  1713. /* no ccw's were created */
  1714. if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
  1715. return FALSE;
  1716. /* need to cache orig list address to remove from hash_table if empty */
  1717. mono_cominterop_lock ();
  1718. ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
  1719. mono_cominterop_unlock ();
  1720. if (!ccw_list)
  1721. return FALSE;
  1722. ccw_list_item = ccw_list;
  1723. while (ccw_list_item) {
  1724. MonoCCW* ccw_iter = ccw_list_item->data;
  1725. MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
  1726. /* Looks like the GC NULLs the weakref handle target before running the
  1727. * finalizer. So if we get a NULL target, destroy the CCW as well. */
  1728. if (!handle_target || handle_target == object) {
  1729. /* remove all interfaces */
  1730. g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
  1731. g_hash_table_destroy (ccw_iter->vtable_hash);
  1732. /* get next before we delete */
  1733. ccw_list_item = g_list_next(ccw_list_item);
  1734. /* remove ccw from list */
  1735. ccw_list = g_list_remove (ccw_list, ccw_iter);
  1736. #ifdef HOST_WIN32
  1737. if (ccw_iter->free_marshaler)
  1738. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
  1739. #endif
  1740. g_free (ccw_iter);
  1741. }
  1742. else
  1743. ccw_list_item = g_list_next(ccw_list_item);
  1744. }
  1745. /* if list is empty remove original address from hash */
  1746. if (g_list_length (ccw_list) == 0)
  1747. g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
  1748. return TRUE;
  1749. }
  1750. /**
  1751. * cominterop_get_managed_wrapper_adjusted:
  1752. * @method: managed COM Interop method
  1753. *
  1754. * Returns: the generated method to call with signature matching
  1755. * the unmanaged COM Method signature
  1756. */
  1757. static MonoMethod *
  1758. cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
  1759. {
  1760. static MonoMethod *get_hr_for_exception = NULL;
  1761. MonoMethod *res = NULL;
  1762. MonoMethodBuilder *mb;
  1763. MonoMarshalSpec **mspecs;
  1764. MonoMethodSignature *sig, *sig_native;
  1765. MonoExceptionClause *main_clause = NULL;
  1766. int pos_leave;
  1767. int hr = 0;
  1768. int i;
  1769. gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
  1770. if (!get_hr_for_exception)
  1771. get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
  1772. sig = mono_method_signature (method);
  1773. /* create unmanaged wrapper */
  1774. mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
  1775. sig_native = cominterop_method_signature (method);
  1776. mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
  1777. mono_method_get_marshal_info (method, mspecs);
  1778. /* move managed args up one */
  1779. for (i = sig->param_count; i >= 1; i--)
  1780. mspecs [i+1] = mspecs [i];
  1781. /* first arg is IntPtr for interface */
  1782. mspecs [1] = NULL;
  1783. /* move return spec to last param */
  1784. if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
  1785. mspecs [sig_native->param_count] = mspecs [0];
  1786. mspecs [0] = NULL;
  1787. if (!preserve_sig) {
  1788. hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
  1789. }
  1790. else if (!MONO_TYPE_IS_VOID (sig->ret))
  1791. hr = mono_mb_add_local (mb, sig->ret);
  1792. /* try */
  1793. main_clause = g_new0 (MonoExceptionClause, 1);
  1794. main_clause->try_offset = mono_mb_get_label (mb);
  1795. /* load last param to store result if not preserve_sig and not void */
  1796. if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
  1797. mono_mb_emit_ldarg (mb, sig_native->param_count-1);
  1798. /* the CCW -> object conversion */
  1799. mono_mb_emit_ldarg (mb, 0);
  1800. mono_mb_emit_icon (mb, FALSE);
  1801. mono_mb_emit_icall (mb, cominterop_get_ccw_object);
  1802. for (i = 0; i < sig->param_count; i++)
  1803. mono_mb_emit_ldarg (mb, i+1);
  1804. mono_mb_emit_managed_call (mb, method, NULL);
  1805. if (!MONO_TYPE_IS_VOID (sig->ret)) {
  1806. if (!preserve_sig) {
  1807. MonoClass *rclass = mono_class_from_mono_type (sig->ret);
  1808. if (rclass->valuetype) {
  1809. mono_mb_emit_op (mb, CEE_STOBJ, rclass);
  1810. } else {
  1811. mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
  1812. }
  1813. } else
  1814. mono_mb_emit_stloc (mb, hr);
  1815. }
  1816. pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
  1817. /* Main exception catch */
  1818. main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
  1819. main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
  1820. main_clause->data.catch_class = mono_defaults.object_class;
  1821. /* handler code */
  1822. main_clause->handler_offset = mono_mb_get_label (mb);
  1823. if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
  1824. mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
  1825. mono_mb_emit_stloc (mb, hr);
  1826. }
  1827. else {
  1828. mono_mb_emit_byte (mb, CEE_POP);
  1829. }
  1830. mono_mb_emit_branch (mb, CEE_LEAVE);
  1831. main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
  1832. /* end catch */
  1833. mono_mb_set_clauses (mb, 1, main_clause);
  1834. mono_mb_patch_branch (mb, pos_leave);
  1835. if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
  1836. mono_mb_emit_ldloc (mb, hr);
  1837. mono_mb_emit_byte (mb, CEE_RET);
  1838. mono_loader_lock ();
  1839. mono_cominterop_lock ();
  1840. res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
  1841. mono_cominterop_unlock ();
  1842. mono_loader_unlock ();
  1843. mono_mb_free (mb);
  1844. for (i = sig_native->param_count; i >= 0; i--)
  1845. if (mspecs [i])
  1846. mono_metadata_free_marshal_spec (mspecs [i]);
  1847. g_free (mspecs);
  1848. return res;
  1849. }
  1850. /**
  1851. * cominterop_mono_string_to_guid:
  1852. *
  1853. * Converts the standard string representation of a GUID
  1854. * to a 16 byte Microsoft GUID.
  1855. */
  1856. static void
  1857. cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
  1858. gunichar2 * chars = mono_string_chars (string);
  1859. int i = 0;
  1860. static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
  1861. for (i = 0; i < sizeof(indexes); i++)
  1862. guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
  1863. }
  1864. static gboolean
  1865. cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
  1866. {
  1867. guint8 klass_guid [16];
  1868. if (cominterop_class_guid (klass, klass_guid))
  1869. return !memcmp (guid, klass_guid, sizeof (klass_guid));
  1870. return FALSE;
  1871. }
  1872. static int STDCALL
  1873. cominterop_ccw_addref (MonoCCWInterface* ccwe)
  1874. {
  1875. gint32 ref_count = 0;
  1876. MonoCCW* ccw = ccwe->ccw;
  1877. g_assert (ccw);
  1878. g_assert (ccw->gc_handle);
  1879. g_assert (ccw->ref_count >= 0);
  1880. ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
  1881. if (ref_count == 1) {
  1882. guint32 oldhandle = ccw->gc_handle;
  1883. g_assert (oldhandle);
  1884. /* since we now have a ref count, alloc a strong handle*/
  1885. ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
  1886. mono_gchandle_free (oldhandle);
  1887. }
  1888. return ref_count;
  1889. }
  1890. static int STDCALL
  1891. cominterop_ccw_release (MonoCCWInterface* ccwe)
  1892. {
  1893. gint32 ref_count = 0;
  1894. MonoCCW* ccw = ccwe->ccw;
  1895. g_assert (ccw);
  1896. g_assert (ccw->ref_count > 0);
  1897. ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
  1898. if (ref_count == 0) {
  1899. /* allow gc of object */
  1900. guint32 oldhandle = ccw->gc_handle;
  1901. g_assert (oldhandle);
  1902. ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
  1903. mono_gchandle_free (oldhandle);
  1904. }
  1905. return ref_count;
  1906. }
  1907. #ifdef HOST_WIN32
  1908. static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
  1909. #endif
  1910. #ifdef HOST_WIN32
  1911. /* All ccw objects are free threaded */
  1912. static int
  1913. cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
  1914. {
  1915. #ifdef HOST_WIN32
  1916. if (!ccw->free_marshaler) {
  1917. int ret = 0;
  1918. gpointer tunk;
  1919. tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
  1920. ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
  1921. }
  1922. if (!ccw->free_marshaler)
  1923. return MONO_E_NOINTERFACE;
  1924. return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
  1925. #else
  1926. return MONO_E_NOINTERFACE;
  1927. #endif
  1928. }
  1929. #endif
  1930. static int STDCALL
  1931. cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
  1932. {
  1933. MonoError error;
  1934. GPtrArray *ifaces;
  1935. MonoClass *itf = NULL;
  1936. int i;
  1937. MonoCCW* ccw = ccwe->ccw;
  1938. MonoClass* klass = NULL;
  1939. MonoClass* klass_iter = NULL;
  1940. MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
  1941. g_assert (object);
  1942. klass = mono_object_class (object);
  1943. if (ppv)
  1944. *ppv = NULL;
  1945. if (!mono_domain_get ())
  1946. mono_thread_attach (mono_get_root_domain ());
  1947. /* handle IUnknown special */
  1948. if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
  1949. *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
  1950. /* remember to addref on QI */
  1951. cominterop_ccw_addref (*ppv);
  1952. return MONO_S_OK;
  1953. }
  1954. /* handle IDispatch special */
  1955. if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
  1956. if (!cominterop_can_support_dispatch (klass))
  1957. return MONO_E_NOINTERFACE;
  1958. *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
  1959. /* remember to addref on QI */
  1960. cominterop_ccw_addref (*ppv);
  1961. return MONO_S_OK;
  1962. }
  1963. #ifdef HOST_WIN32
  1964. /* handle IMarshal special */
  1965. if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
  1966. return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
  1967. }
  1968. #endif
  1969. klass_iter = klass;
  1970. while (klass_iter && klass_iter != mono_defaults.object_class) {
  1971. ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
  1972. g_assert (mono_error_ok (&error));
  1973. if (ifaces) {
  1974. for (i = 0; i < ifaces->len; ++i) {
  1975. MonoClass *ic = NULL;
  1976. ic = g_ptr_array_index (ifaces, i);
  1977. if (cominterop_class_guid_equal (riid, ic)) {
  1978. itf = ic;
  1979. break;
  1980. }
  1981. }
  1982. g_ptr_array_free (ifaces, TRUE);
  1983. }
  1984. if (itf)
  1985. break;
  1986. klass_iter = klass_iter->parent;
  1987. }
  1988. if (itf) {
  1989. *ppv = cominterop_get_ccw (object, itf);
  1990. /* remember to addref on QI */
  1991. cominterop_ccw_addref (*ppv);
  1992. return MONO_S_OK;
  1993. }
  1994. return MONO_E_NOINTERFACE;
  1995. }
  1996. static int STDCALL
  1997. cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
  1998. {
  1999. return MONO_E_NOTIMPL;
  2000. }
  2001. static int STDCALL
  2002. cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
  2003. {
  2004. return MONO_E_NOTIMPL;
  2005. }
  2006. static int STDCALL
  2007. cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
  2008. gunichar2** rgszNames, guint32 cNames,
  2009. guint32 lcid, gint32 *rgDispId)
  2010. {
  2011. return MONO_E_NOTIMPL;
  2012. }
  2013. static int STDCALL
  2014. cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
  2015. gpointer riid, guint32 lcid,
  2016. guint16 wFlags, gpointer pDispParams,
  2017. gpointer pVarResult, gpointer pExcepInfo,
  2018. guint32 *puArgErr)
  2019. {
  2020. return MONO_E_NOTIMPL;
  2021. }
  2022. typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
  2023. typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
  2024. typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
  2025. static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
  2026. static SysStringLenFunc sys_string_len_ms = NULL;
  2027. static SysFreeStringFunc sys_free_string_ms = NULL;
  2028. #ifndef HOST_WIN32
  2029. typedef struct tagSAFEARRAYBOUND {
  2030. ULONG cElements;
  2031. LONG lLbound;
  2032. }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
  2033. #define VT_VARIANT 12
  2034. #endif
  2035. typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
  2036. typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
  2037. typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
  2038. typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
  2039. typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
  2040. typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
  2041. typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
  2042. static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
  2043. static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
  2044. static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
  2045. static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
  2046. static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
  2047. static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
  2048. static SafeArrayCreateFunc safe_array_create_ms = NULL;
  2049. static gboolean
  2050. init_com_provider_ms (void)
  2051. {
  2052. static gboolean initialized = FALSE;
  2053. char *error_msg;
  2054. MonoDl *module = NULL;
  2055. const char* scope = "liboleaut32.so";
  2056. if (initialized)
  2057. return TRUE;
  2058. module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
  2059. if (error_msg) {
  2060. g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
  2061. g_assert_not_reached ();
  2062. return FALSE;
  2063. }
  2064. error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
  2065. if (error_msg) {
  2066. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
  2067. g_assert_not_reached ();
  2068. return FALSE;
  2069. }
  2070. error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
  2071. if (error_msg) {
  2072. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
  2073. g_assert_not_reached ();
  2074. return FALSE;
  2075. }
  2076. error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
  2077. if (error_msg) {
  2078. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
  2079. g_assert_not_reached ();
  2080. return FALSE;
  2081. }
  2082. error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
  2083. if (error_msg) {
  2084. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
  2085. g_assert_not_reached ();
  2086. return FALSE;
  2087. }
  2088. error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
  2089. if (error_msg) {
  2090. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
  2091. g_assert_not_reached ();
  2092. return FALSE;
  2093. }
  2094. error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
  2095. if (error_msg) {
  2096. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
  2097. g_assert_not_reached ();
  2098. return FALSE;
  2099. }
  2100. error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
  2101. if (error_msg) {
  2102. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
  2103. g_assert_not_reached ();
  2104. return FALSE;
  2105. }
  2106. error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
  2107. if (error_msg) {
  2108. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
  2109. g_assert_not_reached ();
  2110. return FALSE;
  2111. }
  2112. error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
  2113. if (error_msg) {
  2114. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
  2115. g_assert_not_reached ();
  2116. return FALSE;
  2117. }
  2118. error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
  2119. if (error_msg) {
  2120. g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
  2121. g_assert_not_reached ();
  2122. return FALSE;
  2123. }
  2124. initialized = TRUE;
  2125. return TRUE;
  2126. }
  2127. gpointer
  2128. mono_string_to_bstr (MonoString *string_obj)
  2129. {
  2130. if (!string_obj)
  2131. return NULL;
  2132. #ifdef HOST_WIN32
  2133. return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
  2134. #else
  2135. if (com_provider == MONO_COM_DEFAULT) {
  2136. int slen = mono_string_length (string_obj);
  2137. /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
  2138. char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
  2139. if (ret == NULL)
  2140. return NULL;
  2141. memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
  2142. * ((guint32 *) ret) = slen * sizeof(gunichar2);
  2143. ret [4 + slen * sizeof(gunichar2)] = 0;
  2144. ret [5 + slen * sizeof(gunichar2)] = 0;
  2145. return ret + 4;
  2146. } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2147. gpointer ret = NULL;
  2148. gunichar* str = NULL;
  2149. guint32 len;
  2150. len = mono_string_length (string_obj);
  2151. str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
  2152. NULL, NULL, NULL);
  2153. ret = sys_alloc_string_len_ms (str, len);
  2154. g_free(str);
  2155. return ret;
  2156. } else {
  2157. g_assert_not_reached ();
  2158. }
  2159. #endif
  2160. }
  2161. MonoString *
  2162. mono_string_from_bstr (gpointer bstr)
  2163. {
  2164. if (!bstr)
  2165. return NULL;
  2166. #ifdef HOST_WIN32
  2167. return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
  2168. #else
  2169. if (com_provider == MONO_COM_DEFAULT) {
  2170. return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
  2171. } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2172. MonoString* str = NULL;
  2173. glong written = 0;
  2174. gunichar2* utf16 = NULL;
  2175. utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
  2176. str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
  2177. g_free (utf16);
  2178. return str;
  2179. } else {
  2180. g_assert_not_reached ();
  2181. }
  2182. #endif
  2183. }
  2184. void
  2185. mono_free_bstr (gpointer bstr)
  2186. {
  2187. if (!bstr)
  2188. return;
  2189. #ifdef HOST_WIN32
  2190. SysFreeString ((BSTR)bstr);
  2191. #else
  2192. if (com_provider == MONO_COM_DEFAULT) {
  2193. g_free (((char *)bstr) - 4);
  2194. } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2195. sys_free_string_ms (bstr);
  2196. } else {
  2197. g_assert_not_reached ();
  2198. }
  2199. #endif
  2200. }
  2201. /* SAFEARRAY marshalling */
  2202. int
  2203. mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
  2204. MonoMarshalSpec *spec,
  2205. int conv_arg, MonoType **conv_arg_type,
  2206. MarshalAction action)
  2207. {
  2208. MonoMethodBuilder *mb = m->mb;
  2209. mono_init_com_types ();
  2210. switch (action) {
  2211. case MARSHAL_ACTION_CONV_IN: {
  2212. if (t->attrs & PARAM_ATTRIBUTE_IN) {
  2213. /* Generates IL code for the following algorithm:
  2214. SafeArray safearray; // safearray_var
  2215. IntPtr indices; // indices_var
  2216. int empty; // empty_var
  2217. if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
  2218. if (!empty) {
  2219. int index=0; // index_var
  2220. do { // label3
  2221. variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
  2222. mono_marshal_safearray_set_value (safearray, indices, elem);
  2223. ++index;
  2224. }
  2225. while (mono_marshal_safearray_next (safearray, indices));
  2226. } // label2
  2227. mono_marshal_safearray_free_indices (indices);
  2228. } // label1
  2229. */
  2230. int safearray_var, indices_var, empty_var, elem_var, index_var;
  2231. guint32 label1 = 0, label2 = 0, label3 = 0;
  2232. static MonoMethod *get_native_variant_for_object = NULL;
  2233. static MonoMethod *get_value_impl = NULL;
  2234. static MonoMethod *variant_clear = NULL;
  2235. conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  2236. indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  2237. empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  2238. if (t->byref) {
  2239. mono_mb_emit_ldarg (mb, argnum);
  2240. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  2241. } else
  2242. mono_mb_emit_ldarg (mb, argnum);
  2243. mono_mb_emit_ldloc_addr (mb, safearray_var);
  2244. mono_mb_emit_ldloc_addr (mb, indices_var);
  2245. mono_mb_emit_ldloc_addr (mb, empty_var);
  2246. mono_mb_emit_icall (mb, mono_marshal_safearray_create);
  2247. label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  2248. mono_mb_emit_ldloc (mb, empty_var);
  2249. label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  2250. index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
  2251. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2252. mono_mb_emit_stloc (mb, index_var);
  2253. label3 = mono_mb_get_label (mb);
  2254. if (!get_value_impl)
  2255. get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
  2256. g_assert (get_value_impl);
  2257. if (t->byref) {
  2258. mono_mb_emit_ldarg (mb, argnum);
  2259. mono_mb_emit_byte (mb, CEE_LDIND_REF);
  2260. } else
  2261. mono_mb_emit_ldarg (mb, argnum);
  2262. mono_mb_emit_ldloc (mb, index_var);
  2263. mono_mb_emit_managed_call (mb, get_value_impl, NULL);
  2264. if (!get_native_variant_for_object)
  2265. get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
  2266. g_assert (get_native_variant_for_object);
  2267. elem_var = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
  2268. mono_mb_emit_ldloc_addr (mb, elem_var);
  2269. mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
  2270. mono_mb_emit_ldloc (mb, safearray_var);
  2271. mono_mb_emit_ldloc (mb, indices_var);
  2272. mono_mb_emit_ldloc_addr (mb, elem_var);
  2273. mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
  2274. if (!variant_clear)
  2275. variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
  2276. mono_mb_emit_ldloc_addr (mb, elem_var);
  2277. mono_mb_emit_managed_call (mb, variant_clear, NULL);
  2278. mono_mb_emit_add_to_local (mb, index_var, 1);
  2279. mono_mb_emit_ldloc (mb, safearray_var);
  2280. mono_mb_emit_ldloc (mb, indices_var);
  2281. mono_mb_emit_icall (mb, mono_marshal_safearray_next);
  2282. mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
  2283. mono_mb_patch_short_branch (mb, label2);
  2284. mono_mb_emit_ldloc (mb, indices_var);
  2285. mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
  2286. mono_mb_patch_short_branch (mb, label1);
  2287. }
  2288. break;
  2289. }
  2290. case MARSHAL_ACTION_PUSH:
  2291. if (t->byref)
  2292. mono_mb_emit_ldloc_addr (mb, conv_arg);
  2293. else
  2294. mono_mb_emit_ldloc (mb, conv_arg);
  2295. break;
  2296. case MARSHAL_ACTION_CONV_OUT: {
  2297. if (t->attrs & PARAM_ATTRIBUTE_OUT) {
  2298. /* Generates IL code for the following algorithm:
  2299. Array result; // result_var
  2300. IntPtr indices; // indices_var
  2301. int empty; // empty_var
  2302. bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
  2303. if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
  2304. if (!empty) {
  2305. int index=0; // index_var
  2306. do { // label3
  2307. if (!byValue || (index < parameter.Length)) {
  2308. object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
  2309. result.SetValueImpl(elem, index);
  2310. }
  2311. ++index;
  2312. }
  2313. while (mono_marshal_safearray_next(safearray, indices));
  2314. } // label2
  2315. mono_marshal_safearray_end(safearray, indices);
  2316. } // label1
  2317. if (!byValue)
  2318. return result;
  2319. */
  2320. int result_var, indices_var, empty_var, elem_var, index_var;
  2321. guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
  2322. static MonoMethod *get_object_for_native_variant = NULL;
  2323. static MonoMethod *set_value_impl = NULL;
  2324. gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
  2325. result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  2326. indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  2327. empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  2328. mono_mb_emit_ldloc (mb, conv_arg);
  2329. mono_mb_emit_ldloc_addr (mb, result_var);
  2330. mono_mb_emit_ldloc_addr (mb, indices_var);
  2331. mono_mb_emit_ldloc_addr (mb, empty_var);
  2332. mono_mb_emit_ldarg (mb, argnum);
  2333. if (byValue)
  2334. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2335. else
  2336. mono_mb_emit_byte (mb, CEE_LDC_I4_1);
  2337. mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
  2338. label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
  2339. mono_mb_emit_ldloc (mb, empty_var);
  2340. label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
  2341. index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
  2342. mono_mb_emit_byte (mb, CEE_LDC_I4_0);
  2343. mono_mb_emit_stloc (mb, index_var);
  2344. label3 = mono_mb_get_label (mb);
  2345. if (byValue) {
  2346. mono_mb_emit_ldloc (mb, index_var);
  2347. mono_mb_emit_ldarg (mb, argnum);
  2348. mono_mb_emit_byte (mb, CEE_LDLEN);
  2349. label4 = mono_mb_emit_branch (mb, CEE_BGE);
  2350. }
  2351. mono_mb_emit_ldloc (mb, conv_arg);
  2352. mono_mb_emit_ldloc (mb, indices_var);
  2353. mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
  2354. if (!get_object_for_native_variant)
  2355. get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
  2356. g_assert (get_object_for_native_variant);
  2357. if (!set_value_impl)
  2358. set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
  2359. g_assert (set_value_impl);
  2360. elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
  2361. mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
  2362. mono_mb_emit_stloc (mb, elem_var);
  2363. mono_mb_emit_ldloc (mb, result_var);
  2364. mono_mb_emit_ldloc (mb, elem_var);
  2365. mono_mb_emit_ldloc (mb, index_var);
  2366. mono_mb_emit_managed_call (mb, set_value_impl, NULL);
  2367. if (byValue)
  2368. mono_mb_patch_short_branch (mb, label4);
  2369. mono_mb_emit_add_to_local (mb, index_var, 1);
  2370. mono_mb_emit_ldloc (mb, conv_arg);
  2371. mono_mb_emit_ldloc (mb, indices_var);
  2372. mono_mb_emit_icall (mb, mono_marshal_safearray_next);
  2373. mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
  2374. mono_mb_patch_short_branch (mb, label2);
  2375. mono_mb_emit_ldloc (mb, conv_arg);
  2376. mono_mb_emit_ldloc (mb, indices_var);
  2377. mono_mb_emit_icall (mb, mono_marshal_safearray_end);
  2378. mono_mb_patch_short_branch (mb, label1);
  2379. if (!byValue) {
  2380. mono_mb_emit_ldarg (mb, argnum);
  2381. mono_mb_emit_ldloc (mb, result_var);
  2382. mono_mb_emit_byte (mb, CEE_STIND_REF);
  2383. }
  2384. }
  2385. break;
  2386. }
  2387. default:
  2388. g_assert_not_reached ();
  2389. }
  2390. return conv_arg;
  2391. }
  2392. static
  2393. guint32 mono_marshal_safearray_get_dim (gpointer safearray)
  2394. {
  2395. guint32 result=0;
  2396. #ifdef HOST_WIN32
  2397. result = SafeArrayGetDim (safearray);
  2398. #else
  2399. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2400. result = safe_array_get_dim_ms (safearray);
  2401. } else {
  2402. g_assert_not_reached ();
  2403. }
  2404. #endif
  2405. return result;
  2406. }
  2407. static
  2408. int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
  2409. {
  2410. int result=MONO_S_OK;
  2411. #ifdef HOST_WIN32
  2412. result = SafeArrayGetLBound (psa, nDim, plLbound);
  2413. #else
  2414. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2415. result = safe_array_get_lbound_ms (psa, nDim, plLbound);
  2416. } else {
  2417. g_assert_not_reached ();
  2418. }
  2419. #endif
  2420. return result;
  2421. }
  2422. static
  2423. int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
  2424. {
  2425. int result=MONO_S_OK;
  2426. #ifdef HOST_WIN32
  2427. result = SafeArrayGetUBound (psa, nDim, plUbound);
  2428. #else
  2429. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2430. result = safe_array_get_ubound_ms (psa, nDim, plUbound);
  2431. } else {
  2432. g_assert_not_reached ();
  2433. }
  2434. #endif
  2435. return result;
  2436. }
  2437. static gboolean
  2438. mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
  2439. {
  2440. int dim;
  2441. uintptr_t *sizes;
  2442. intptr_t *bounds;
  2443. MonoClass *aklass;
  2444. int i;
  2445. gboolean bounded = FALSE;
  2446. #ifndef HOST_WIN32
  2447. // If not on windows, check that the MS provider is used as it is
  2448. // required for SAFEARRAY support.
  2449. // If SAFEARRAYs are not supported, returning FALSE from this
  2450. // function will prevent the other mono_marshal_safearray_xxx functions
  2451. // from being called.
  2452. if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
  2453. return FALSE;
  2454. }
  2455. #endif
  2456. (*(int*)empty) = TRUE;
  2457. if (safearray != NULL) {
  2458. dim = mono_marshal_safearray_get_dim (safearray);
  2459. if (dim > 0) {
  2460. *indices = g_malloc (dim * sizeof(int));
  2461. sizes = alloca (dim * sizeof(uintptr_t));
  2462. bounds = alloca (dim * sizeof(intptr_t));
  2463. for (i=0; i<dim; ++i) {
  2464. glong lbound, ubound;
  2465. int cursize;
  2466. int hr;
  2467. hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
  2468. if (hr < 0) {
  2469. cominterop_raise_hr_exception (hr);
  2470. }
  2471. if (lbound != 0)
  2472. bounded = TRUE;
  2473. hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
  2474. if (hr < 0) {
  2475. cominterop_raise_hr_exception (hr);
  2476. }
  2477. cursize = ubound-lbound+1;
  2478. sizes [i] = cursize;
  2479. bounds [i] = lbound;
  2480. ((int*)*indices) [i] = lbound;
  2481. if (cursize != 0)
  2482. (*(int*)empty) = FALSE;
  2483. }
  2484. if (allocateNewArray) {
  2485. aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
  2486. *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
  2487. } else {
  2488. *result = parameter;
  2489. }
  2490. }
  2491. }
  2492. return TRUE;
  2493. }
  2494. static
  2495. gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
  2496. {
  2497. gpointer result;
  2498. #ifdef HOST_WIN32
  2499. int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
  2500. if (hr < 0) {
  2501. cominterop_raise_hr_exception (hr);
  2502. }
  2503. #else
  2504. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2505. int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
  2506. if (hr < 0) {
  2507. cominterop_raise_hr_exception (hr);
  2508. }
  2509. } else {
  2510. g_assert_not_reached ();
  2511. }
  2512. #endif
  2513. return result;
  2514. }
  2515. static
  2516. gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
  2517. {
  2518. int i;
  2519. int dim = mono_marshal_safearray_get_dim (safearray);
  2520. gboolean ret= TRUE;
  2521. int *pIndices = (int*) indices;
  2522. int hr;
  2523. for (i=dim-1; i>=0; --i)
  2524. {
  2525. glong lbound, ubound;
  2526. hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
  2527. if (hr < 0) {
  2528. cominterop_raise_hr_exception (hr);
  2529. }
  2530. if (++pIndices[i] <= ubound) {
  2531. break;
  2532. }
  2533. hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
  2534. if (hr < 0) {
  2535. cominterop_raise_hr_exception (hr);
  2536. }
  2537. pIndices[i] = lbound;
  2538. if (i == 0)
  2539. ret = FALSE;
  2540. }
  2541. return ret;
  2542. }
  2543. static
  2544. void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
  2545. {
  2546. g_free(indices);
  2547. #ifdef HOST_WIN32
  2548. SafeArrayDestroy (safearray);
  2549. #else
  2550. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2551. safe_array_destroy_ms (safearray);
  2552. } else {
  2553. g_assert_not_reached ();
  2554. }
  2555. #endif
  2556. }
  2557. static gboolean
  2558. mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
  2559. {
  2560. int dim;
  2561. SAFEARRAYBOUND *bounds;
  2562. int i;
  2563. int max_array_length;
  2564. #ifndef HOST_WIN32
  2565. // If not on windows, check that the MS provider is used as it is
  2566. // required for SAFEARRAY support.
  2567. // If SAFEARRAYs are not supported, returning FALSE from this
  2568. // function will prevent the other mono_marshal_safearray_xxx functions
  2569. // from being called.
  2570. if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
  2571. return FALSE;
  2572. }
  2573. #endif
  2574. max_array_length = mono_array_length (input);
  2575. dim = ((MonoObject *)input)->vtable->klass->rank;
  2576. *indices = g_malloc (dim * sizeof (int));
  2577. bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
  2578. (*(int*)empty) = (max_array_length == 0);
  2579. if (dim > 1) {
  2580. for (i=0; i<dim; ++i) {
  2581. ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
  2582. bounds [i].cElements = input->bounds [i].length;
  2583. }
  2584. } else {
  2585. ((int*)*indices) [0] = 0;
  2586. bounds [0].cElements = max_array_length;
  2587. bounds [0].lLbound = 0;
  2588. }
  2589. #ifdef HOST_WIN32
  2590. *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
  2591. #else
  2592. *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
  2593. #endif
  2594. return TRUE;
  2595. }
  2596. static
  2597. void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
  2598. {
  2599. #ifdef HOST_WIN32
  2600. int hr = SafeArrayPutElement (safearray, indices, value);
  2601. if (hr < 0)
  2602. cominterop_raise_hr_exception (hr);
  2603. #else
  2604. if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
  2605. int hr = safe_array_put_element_ms (safearray, indices, value);
  2606. if (hr < 0) {
  2607. cominterop_raise_hr_exception (hr);
  2608. }
  2609. } else
  2610. g_assert_not_reached ();
  2611. #endif
  2612. }
  2613. static
  2614. void mono_marshal_safearray_free_indices (gpointer indices)
  2615. {
  2616. g_free (indices);
  2617. }
  2618. #else /* DISABLE_COM */
  2619. void
  2620. mono_cominterop_init (void)
  2621. {
  2622. /*FIXME
  2623. This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
  2624. If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
  2625. g_assert.
  2626. The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
  2627. emit an exception in the generated IL.
  2628. */
  2629. register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
  2630. register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
  2631. register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
  2632. }
  2633. void
  2634. mono_cominterop_cleanup (void)
  2635. {
  2636. }
  2637. void
  2638. cominterop_release_all_rcws (void)
  2639. {
  2640. }
  2641. gboolean
  2642. mono_marshal_free_ccw (MonoObject* object)
  2643. {
  2644. return FALSE;
  2645. }
  2646. gpointer
  2647. mono_string_to_bstr (MonoString *string_obj)
  2648. {
  2649. if (!string_obj)
  2650. return NULL;
  2651. #ifdef HOST_WIN32
  2652. return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
  2653. #else
  2654. {
  2655. int slen = mono_string_length (string_obj);
  2656. /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
  2657. char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
  2658. if (ret == NULL)
  2659. return NULL;
  2660. memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
  2661. * ((guint32 *) ret) = slen * sizeof(gunichar2);
  2662. ret [4 + slen * sizeof(gunichar2)] = 0;
  2663. ret [5 + slen * sizeof(gunichar2)] = 0;
  2664. return ret + 4;
  2665. }
  2666. #endif
  2667. }
  2668. MonoString *
  2669. mono_string_from_bstr (gpointer bstr)
  2670. {
  2671. if (!bstr)
  2672. return NULL;
  2673. #ifdef HOST_WIN32
  2674. return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
  2675. #else
  2676. return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
  2677. #endif
  2678. }
  2679. void
  2680. mono_free_bstr (gpointer bstr)
  2681. {
  2682. if (!bstr)
  2683. return;
  2684. #ifdef HOST_WIN32
  2685. SysFreeString ((BSTR)bstr);
  2686. #else
  2687. g_free (((char *)bstr) - 4);
  2688. #endif
  2689. }
  2690. int
  2691. ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
  2692. {
  2693. g_assert_not_reached ();
  2694. return 0;
  2695. }
  2696. int
  2697. ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
  2698. {
  2699. g_assert_not_reached ();
  2700. return 0;
  2701. }
  2702. int
  2703. ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
  2704. {
  2705. g_assert_not_reached ();
  2706. return 0;
  2707. }
  2708. #endif /* DISABLE_COM */
  2709. MonoString *
  2710. ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
  2711. {
  2712. MONO_ARCH_SAVE_REGS;
  2713. return mono_string_from_bstr(ptr);
  2714. }
  2715. gpointer
  2716. ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
  2717. {
  2718. MONO_ARCH_SAVE_REGS;
  2719. return mono_string_to_bstr(ptr);
  2720. }
  2721. void
  2722. ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
  2723. {
  2724. MONO_ARCH_SAVE_REGS;
  2725. mono_free_bstr (ptr);
  2726. }