c# - qué - que es una clase en programacion
Pasar una instancia de clase C#a código administrado desde JavaScript a través de COM (2)
Tienes que hacer dos cosas
Descubre el tipo de objeto como se describe aquí .
Extraiga el objeto real de él usando Marshal.GetObjectForIUnknown (lea hasta el final, hay una interfaz para implementar).
El esquema básico de mi problema se muestra en el código a continuación. Estoy alojando un control WebBrowser en un formulario y proporcionando un ObjectForScripting
con dos métodos: GiveMeAGizmo
y GiveMeAGizmoUser
. Ambos métodos devuelven las instancias de clase respectivas:
[ComVisible]
public class Gizmo
{
public string name { get; set; }
}
[ComVisible]
public class GizmoUser
{
public void doSomethingWith(object oGizmo)
{
Gizmo g = (Gizmo) oGizmo;
System.Diagnostics.Debug.WriteLine(g.name);
}
}
En JavaScript, creo una instancia de ambas clases, pero necesito pasar la primera instancia a un método en la segunda instancia. El código JS se ve un poco así:
var
// Returns a Gizmo instance
gizmo = window.external.GiveMeAGizmo(),
// Returns a GizmoUser instance
gUser = window.external.GiveMeAGizmoUser();
gizmo.name = ''hello'';
// Passes Gizmo instance back to C# code
gUser.doSomethingWith(gizmo);
Aquí es donde choqué contra una pared. Mi método C # GizmoUser.doSomethingWith()
no puede devolver el objeto a un tipo de Gizmo. Lanza el siguiente error:
No se ha podido convertir el objeto COM del tipo ''System .__ ComObject'' al tipo de interfaz ''Gizmo''
Inseguro de cómo proceder, intenté un par de otras cosas:
- Safe casting
Gizmo g = oGizmo as Gizmo;
(g
esnull
) - Hacer que las clases implementen
IDispatch
yInvokeMember
aInvokeMember
, como se explica aquí . El miembro "nombre" esnull
.
Necesito que esto funcione con la versión de .NET Framework menor que 4.0, por lo que no puedo usar dynamic
. ¿Alguien sabe cómo puedo hacer que esto funcione?
Que interesante. Cuando recibimos el objeto oGizmo
en doSomethingWith
, es del tipo Windows Runtime Object
. Este comportamiento es coherente entre JavaScript y VBScript.
Ahora, si especificamos explícitamente MarshalAs(UnmanagedType.IUnknown)
en el valor de retorno del método GiveMeAGizmo()
, todo funciona bien , el objeto puede ser devuelto a Gizmo
dentro de doSomethingWith
:
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch)]
public class ObjectForScripting
{
[return: MarshalAs(UnmanagedType.IUnknown)]
public object GiveMeAGizmo()
{
return new Gizmo();
}
public object GiveMeAGizmoUser()
{
return new GizmoUser();
}
}
Aún así, si especificamos UnmanagedType.IDispatch
o UnmanagedType.Struct
(el predeterminado que clasifica el objeto como COM VARIANT
), el problema está de vuelta.
Por lo tanto, hay una solución, pero no hay una explicación razonable para dicho comportamiento de interoperabilidad COM, hasta el momento.
[ACTUALIZACIÓN] Algunos experimentos más, a continuación. Observe cómo la obtención de gizmo1
es exitosa, mientras que gizmo2
no es:
C # :
// pass a Gizmo object to JavaScript
this.webBrowser.Document.InvokeScript("SetGizmo", new Object[] { new Gizmo()});
// get it back, this works
var gizmo1 = (Gizmo)this.webBrowser.Document.InvokeScript("GetGizmo");
// get a new Gizmo, via window.external.GiveMeAGizmo()
// this fails
var gizmo2 = (Gizmo)this.webBrowser.Document.InvokeScript("GetGizmo2");
JavaScript:
var _gizmo;
function SetGizmo(gizmo) { _gizmo = gizmo; }
function GetGizmo() { return _gizmo; }
function GetGizmo2() { return window.external.GiveMeAGizmo(); }
Es solo una suposición, pero creo que dicho comportamiento podría tener algo que ver con los conjuntos de permisos de seguridad .NET, impuestos por WebBrowser.ObjectForScripting
.