EDITAR: He escrito los resultados como una publicación de blog .
El compilador de C # trata los tipos COM de forma algo mágica. Por ejemplo, esta declaración parece normal ...
Word.Application app = new Word.Application();
... hasta que te das cuenta de que Application
es una interfaz. ¿Llamando a un constructor en una interfaz? Yoiks! Esto en realidad se traduce en una llamada a Type.GetTypeFromCLSID()
y otra a Activator.CreateInstance
.
Además, en C # 4, puede usar argumentos que no sean de referencia para los ref
parámetros, y el compilador simplemente agrega una variable local para pasar por referencia, descartando los resultados:
// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");
(Sí, faltan muchos argumentos. ¿No son buenos los parámetros opcionales? :)
Estoy tratando de investigar el comportamiento del compilador, y no puedo falsificar la primera parte. Puedo hacer la segunda parte sin problema:
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
void Foo(ref int x);
}
class Test
{
static void Main()
{
Dummy dummy = null;
dummy.Foo(10);
}
}
Me gustaría poder escribir:
Dummy dummy = new Dummy();
aunque. Obviamente estallará en el momento de la ejecución, pero está bien. Solo estoy experimentando.
Los otros atributos agregados por el compilador para los PIA COM vinculados ( CompilerGenerated
y TypeIdentifier
) no parecen hacer el truco ... ¿cuál es la salsa mágica?
fuente
dynamic
... estamos demasiado acostumbrados al tipeo estático / fuerte para ver por qué sería importante fuera de COM.Respuestas:
De ninguna manera soy un experto en esto, pero recientemente me topé con lo que creo que quieres: la clase de atributo CoClass .
Vea mi respuesta a una pregunta similar sobre la API de Microsoft Speech , donde puede "instanciar" la interfaz
SpVoice
(pero realmente, está creando instanciasSPVoiceClass
).fuente
Entre tú y Michael casi tienes las piezas juntas. Creo que así es como funciona. (No escribí el código, por lo que podría estar un poco equivocado, pero estoy bastante seguro de que así es como funciona).
Si:
entonces el código se genera como (IPIAINTERFACE) Activator.CreateInstance (Type.GetTypeFromClsid (GUID OF COCLASSTYPE))
Si:
entonces el código se genera como si dijeras "nuevo COCLASSTYPE ()".
Jon, siéntete libre de molestarme a mí o a Sam directamente si tienes preguntas sobre estas cosas. FYI, Sam es el experto en esta característica.
fuente
De acuerdo, esto es solo para poner un poco más de carne en la respuesta de Michael (puede agregarla si lo desea, en cuyo caso eliminaré esta).
Mirando el PIA original para Word. Aplicación, hay tres tipos involucrados (ignorando los eventos):
Hay dos interfaces por razones de las que Eric Lippert habla en otra respuesta . Y allí, como dijiste, está el
CoClass
- tanto en términos de la clase misma como del atributo en laApplication
interfaz.Ahora, si usamos enlaces PIA en C # 4, algo de esto está incrustado en el binario resultante ... pero no todo. Una aplicación que solo crea una instancia de
Application
termina con estos tipos:No
ApplicationClass
, probablemente porque se cargará dinámicamente desde el tipo COM real en el momento de la ejecución.Otra cosa interesante es la diferencia en el código entre la versión vinculada y la versión no vinculada. Si descompilas la línea
en la versión referenciada termina como:
mientras que en la versión vinculada termina como
Así que parece que el "verdadero" PIA necesita el
CoClass
atributo, pero la versión vinculada no lo hace porque no es unCoClass
compilador puede en realidad referencia. Tiene que hacerlo dinámicamente.Podría intentar falsificar una interfaz COM utilizando esta información y ver si puedo conseguir que el compilador lo vincule ...
fuente
Solo para agregar un poco de confirmación a la respuesta de Michael:
El siguiente código compila y ejecuta:
Necesita tanto el
ComImportAttribute
como elGuidAttribute
para que funcione.También tenga en cuenta la información cuando pase el mouse sobre
new IFoo()
: Intellisense recoge correctamente la información: ¡Bien!fuente