Pregunta


La pregunta

Mi pregunta es: ¿Es compatible C # nativly con el enlace reciente de IDispatch?


Pretender estoy intentando automatizar Office, a la vez que soy compatible con cualquier versión que haya instalado el cliente.

En el mundo .NET, si desarrolló con Office 2000 instalado, se requiere que Office 2000 tenga cada desarrollador y cada cliente, desde ahora hasta el fin de los tiempos.

En el mundo anterior a .NET, usamos COM para hablar con las aplicaciones de Office.

Por ejemplo:

1) Utilice la versión independiente ProgID

"Excel.Application"

que se resuelve a:

clsid = {00024500-0000-0000-C000-000000000046}

y luego utilizando COM, pedimos que una de estas clases se cree en un objeto:

IUnknown unk;
CoCreateInstance(
    clsid, 
    null,
    CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    IUnknown, 
    out unk);

Y ahora nos vamos a las carreras, capaces de usar Excel desde dentro de mi aplicación. Por supuesto, si realmente quiere usar el objeto, debe llamar para tener alguna forma de llamar a los métodos.

Nosotros podríamos conocer las diversas declaraciones de interfaz , traducidas a nuestro idioma. Esta técnica es buena porque obtenemos

  • enlace temprano
  • código-insight
  • compilación de comprobación de sintaxis de tipo

y algún código de ejemplo podría ser:

Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;

Pero hay una desventaja en el uso de interfaces: tenemos que conocer las diversas declaraciones de interfaces, traducidas a nuestro idioma. Y estamos atascados con invocaciones basadas en métodos, teniendo que especificar todos los parámetros, por ejemplo:

ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);

Esto ha demostrado, en el mundo real, tener tales inconvenientes que desistiríamos de buena gana:

  • enlace temprano
  • código-insight
  • verificación de sintaxis de tiempo de compilación

y en su lugar use IDispatch enlace tardío:

Variant xl = (IDispatch)unk;
Variant newWorksheet = xl.Worksheets.Add();

Debido a que la automatización de Excel fue diseñada para VB Script, se pueden omitir muchos parámetros, incluso cuando no hay sobrecarga sin ellos.

Nota: No confunda mi ejemplo de Excel con una razón por la que quiero usar IDispatch. No todos los objetos COM son Excel. Algunos objetos COM no tienen soporte que no sea a través de IDispatch.

¿Fue útil?

Solución

Relativamente, se puede usar el enlace IDispatch de enlace tardío en C #.

http://support.microsoft.com/kb/302902

Aquí hay algunos ejemplos para usar Excel. De esta manera, no es necesario agregar una dependencia innecesaria en el PIA de Microsoft:

//Create XL
Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

//Get the workbooks collection.
//   books = xl.Workbooks;
Object books = xl.GetType().InvokeMember( "Workbooks", 
      BindingFlags.GetProperty, null, xl, null);

//Add a new workbook.
//   book = books.Add();
Objet book = books.GetType().InvokeMember( "Add", 
      BindingFlags.InvokeMethod, null, books, null );

//Get the worksheets collection.
//   sheets = book.Worksheets;
Object sheets = book.GetType().InvokeMember( "Worksheets",
      BindingFlags.GetProperty, null, book, null );

Object[] parameters;

//Get the first worksheet.
//   sheet = sheets.Item[1]
parameters = new Object[1];
parameters[0] = 1;
Object sheet = sheets.GetType().InvokeMember( "Item", 
      BindingFlags.GetProperty, null, sheets, parameters );

//Get a range object that contains cell A1.
//   range = sheet.Range["A1];
parameters = new Object[2];
parameters[0] = "A1";
parameters[1] = Missing.Value;
Object range = sheet.GetType().InvokeMember( "Range",
      BindingFlags.GetProperty, null, sheet, parameters );

//Write "Hello, World!" in cell A1.
//   range.Value = "Hello, World!";
parameters = new Object[1];
parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, 
      null, range, parameters );

//Return control of Excel to the user.
//   xl.Visible = true;
//   xl.UserControl = true;
parameters = new Object[1];
parameters[0] = true;
xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty,
      null, xl, Parameters );
xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty,
      null, xl, Parameters );

Otros consejos

Debe esperar a que aparezca C # 4.0 para obtener el enlace que está buscando. Cada vez que necesito capacidades de interoperabilidad, vuelvo al modo VB.Net para poder aprovechar las capacidades COM de las que C # parece carecer.

El método simple que utilizo es crear una clase en VB.Net que haga el trabajo de IDispatch y luego exponer los métodos que deseo usar como métodos de mi envoltorio y luego puedo llamarlos a voluntad desde mi código C #. No es la más elegante de las soluciones, pero me ha sacado uno o dos problemas en los últimos meses.

La palabra clave dynamic de

C # 4 admite IDispatch y enlace en tiempo de ejecución. Puede leer serie dinámica de Sam Ng para obtener más información

Ah, y C # 4 solo está disponible como CTP en la actualidad. Tendrá que esperar a que Visual Studio vNext o usar la versión beta (que se ejecuta en una PC virtual con Windows Server 2008) para usarla.

Probablemente pueda salirse con un código mucho mejor en C # 2.0 / 3.0 si se toma el tiempo para escribir una interfaz contiene los métodos y las propiedades que desea del objeto y agrega algunos atributos (lo escribo desde la memoria, por lo que los detalles pueden no ser correctos, pero juro que me funcionó ...)

    using System.Runtime.Interopservices;

    [Guid("00024500-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    interface IExcel
    {
      // sample property
      string Name{get;}
      // more properties
    }

    // and somewhere else
    void main()
    {
      Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
      IExcel excel = (IExcel)xl;
      string name = xl.name
    }

Como se mencionó anteriormente, el código no funcionará de manera inmediata, es más una sugerencia sobre qué es lo que debe buscar en msdn.

Como han dicho otros: utilizando " dinámico " de c # 4 palabra clave rocas. Este es un ejemplo simple: es mucho más sucinto que usar " InvokeMethod "

dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
dynamic books = xl.Workbooks;
dynamic book = books.Add();

Console.WriteLine(books.Count);     //Writes 1

foreach (dynamic b in books)        
{
Console.WriteLine(b.Name);      //Writes "Book1"
}
hola amigo Tengo 2 proyectos de Codeplex actualmente para resolver este problema.

el primero es LateBindingApi.Excel http://excel.codeplex.com Se asignó una llamada de invocación de enlace tardío al bien conocido modelo de objetos. Este fue un proyecto de prueba para el siguiente proyecto.

el segundo es un CodeGenerator http://latebindingapi.codeplex.com La herramienta crea c # proyectos desde las bibliotecas de tipos COM. los proyectos generados incluyen objetos de mapeador con enlace de acceso al servidor COM. lo más destacado es que la herramienta convierte las bibliotecas de tipos COM en diferentes versiones en un solo proyecto (por ejemplo, excel 9,10,11) y marcó todas las entidades con un atributo de biblioteca de soporte autodefinido. He analizado todas las aplicaciones de Office en la versión 9,10,11,12,14 con esta herramienta ahora y genero una solución c #, está disponible como versión beta probada con código de muestra en la página principal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top