+ res = mono_mb_create_and_cache (cache, sig,
+ mb, sig, sig->param_count + 16);
+ mono_mb_free (mb);
+
+ return res;
+}
+
+static MonoObject *
+mono_remoting_wrapper (MonoMethod *method, gpointer *params)
+{
+ MonoMethodMessage *msg;
+ MonoTransparentProxy *this;
+ MonoObject *res, *exc;
+ MonoArray *out_args;
+
+ this = *((MonoTransparentProxy **)params [0]);
+
+ g_assert (this);
+ g_assert (((MonoObject *)this)->vtable->klass == mono_defaults.transparent_proxy_class);
+
+ /* skip the this pointer */
+ params++;
+
+ if (this->remote_class->proxy_class->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
+ {
+ int i;
+ MonoMethodSignature *sig = mono_method_signature (method);
+ int count = sig->param_count;
+ gpointer* mparams = (gpointer*) alloca(count*sizeof(gpointer));
+
+ for (i=0; i<count; i++) {
+ MonoClass *class = mono_class_from_mono_type (sig->params [i]);
+ if (class->valuetype) {
+ if (sig->params [i]->byref)
+ mparams[i] = *((gpointer *)params [i]);
+ else
+ mparams[i] = params [i];
+ } else {
+ mparams[i] = *((gpointer**)params [i]);
+ }
+ }
+
+ return mono_runtime_invoke (method, method->klass->valuetype? mono_object_unbox ((MonoObject*)this): this, mparams, NULL);
+ }
+
+ msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
+
+ res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
+
+ if (exc)
+ mono_raise_exception ((MonoException *)exc);
+
+ mono_method_return_message_restore (method, params, out_args);
+
+ return res;
+}
+
+/**
+ * cominterop_get_native_wrapper_adjusted:
+ * @method: managed COM Interop method
+ *
+ * Returns: the generated method to call with signature matching
+ * the unmanaged COM Method signature
+ */
+static MonoMethod *
+cominterop_get_native_wrapper_adjusted (MonoMethod *method)
+{
+ MonoMethod *res;
+ MonoMethodBuilder *mb_native;
+ MonoMarshalSpec **mspecs;
+ MonoMethodSignature *sig, *sig_native;
+ MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
+ int i;
+
+ sig = mono_method_signature (method);
+
+ // create unmanaged wrapper
+ mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
+ sig_native = signature_cominterop (method->klass->image, sig);
+
+ mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
+ memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
+
+ mono_method_get_marshal_info (method, mspecs);
+
+ // move managed args up one
+ for (i = sig->param_count; i >= 1; i--)
+ mspecs[i+1] = mspecs[i];
+
+ // first arg is IntPtr for interface
+ mspecs[1] = NULL;
+
+ // move return spec to last param
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mspecs[sig_native->param_count] = mspecs[0];
+
+ mspecs[0] = NULL;
+
+ mono_marshal_emit_native_wrapper(mb_native, sig_native, piinfo, mspecs, piinfo->addr);
+
+ mono_loader_lock ();
+ mono_marshal_lock ();
+ res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
+ mono_marshal_unlock ();
+ mono_loader_unlock ();
+
+ mono_mb_free (mb_native);
+
+ for (i = sig_native->param_count; i >= 0; i--)
+ if (mspecs [i])
+ mono_metadata_free_marshal_spec (mspecs [i]);
+ g_free (mspecs);
+
+ return res;
+}
+
+/**
+ * cominterop_get_native_wrapper:
+ * @method: managed method
+ *
+ * Returns: the generated method to call
+ */
+static MonoMethod *
+cominterop_get_native_wrapper (MonoMethod *method)
+{
+ MonoMethod *res;
+ GHashTable *cache;
+ MonoMethodBuilder *mb;
+ MonoMethodSignature *sig, *csig;
+
+ g_assert (method);
+
+ cache = method->klass->image->cominterop_wrapper_cache;
+ if ((res = mono_marshal_find_in_cache (cache, method)))
+ return res;
+
+ sig = mono_method_signature (method);
+ mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
+
+ /* if method klass is import, that means method
+ * is really a com call. let interop system emit it.
+ */
+ if (MONO_CLASS_IS_IMPORT(method->klass)) {
+ /* FIXME: we have to call actual class .ctor
+ * instead of just __ComObject .ctor.
+ */
+ if (!strcmp(method->name, ".ctor")) {
+ static MonoMethod *ctor = NULL;
+
+ if (!ctor)
+ ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_managed_call (mb, ctor, NULL);
+ mono_mb_emit_byte (mb, CEE_RET);
+ }
+ else {
+ static MonoMethod * ThrowExceptionForHR = NULL;
+ static MonoMethod * GetInterface = NULL;
+ MonoMethod *adjusted_method;
+ int hr;
+ int retval = 0;
+ int ptr_this;
+ int i;
+ if (!GetInterface)
+ GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+
+ // add local variables
+ hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+ ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ retval = mono_mb_add_local (mb, sig->ret);
+
+ // get the type for the interface the method is defined on
+ // and then get the underlying COM interface for that type
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ptr (mb, method);
+ mono_mb_emit_icall (mb, cominterop_get_method_interface);
+ mono_mb_emit_managed_call (mb, GetInterface, NULL);
+ mono_mb_emit_stloc (mb, ptr_this);
+
+ // arg 1 is unmanaged this pointer
+ mono_mb_emit_ldloc (mb, ptr_this);
+
+ // load args
+ for (i = 1; i <= sig->param_count; i++)
+ mono_mb_emit_ldarg (mb, i);
+
+ // push managed return value as byref last argument
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_ldloc_addr (mb, retval);
+
+ adjusted_method = cominterop_get_native_wrapper_adjusted (method);
+ mono_mb_emit_managed_call (mb, adjusted_method, NULL);
+
+ // store HRESULT to check
+ mono_mb_emit_stloc (mb, hr);
+
+ if (!ThrowExceptionForHR)
+ ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
+ mono_mb_emit_ldloc (mb, hr);
+ mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
+
+ // load return value managed is expecting
+ if (!MONO_TYPE_IS_VOID (sig->ret))
+ mono_mb_emit_ldloc (mb, retval);
+
+ mono_mb_emit_byte (mb, CEE_RET);
+ }
+
+
+ }
+ /* Does this case ever get hit? */
+ else {
+ char *msg = g_strdup ("non imported interfaces on \
+ imported classes is not yet implemented.");
+ mono_mb_emit_exception (mb, "NotSupportedException", msg);
+ }
+ csig = signature_dup (method->klass->image, sig);
+ csig->pinvoke = 0;
+ res = mono_mb_create_and_cache (cache, method,
+ mb, csig, csig->param_count + 16);
+ mono_mb_free (mb);
+ return res;
+}
+
+/**
+ * cominterop_get_invoke:
+ * @method: managed method
+ *
+ * Returns: the generated method that calls the underlying __ComObject
+ * rather than the proxy object.
+ */
+static MonoMethod *
+cominterop_get_invoke (MonoMethod *method)
+{
+ MonoMethodSignature *sig;
+ MonoMethodBuilder *mb;
+ MonoMethod *res;
+ int i, temp_obj;
+ GHashTable* cache = method->klass->image->cominterop_invoke_cache;
+
+ g_assert (method);