PageRenderTime 51ms CodeModel.GetById 9ms 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

Large files files are truncated, but you can click here to view the full file

  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_ob

Large files files are truncated, but you can click here to view the full file