Pergunta


A Pergunta

A minha pergunta é:? Does C # nativly apoiar IDispatch ligação tardia


Finja eu estou tentando automatizar o Office, sendo compatível com qualquer versão que o cliente tenha instalado.

No mundo do .NET se desenvolveu com o Office 2000 instalado, todos os desenvolvedores, e cada cliente, a partir de agora até o fim dos tempos, é necessário ter o Office 2000.

No mundo antes de .NET, usamos COM para conversar com aplicativos do Office.

Por exemplo:

1) Use a versão independente ProgID

"Excel.Application"

que resolve:

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

e, em seguida, usando COM, pedimos para uma dessas classes para ser instanciado em um objeto:

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

E agora estamos fora para as corridas - capaz de usar o Excel de dentro da minha aplicação. Claro, se realmente que você deseja usar o objeto, você tem que chamar ter alguma maneira de chamar métodos.

poderia get ahold das várias Interface declarações, traduzido em nossa língua. Esta técnica é boa, porque nós temos

  • ligação antecipada
  • código-visão
  • tipo de compilação verificação de sintaxe

e algum código de exemplo pode ser:

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

Mas há uma desvantagem de usar interfaces: temos que conseguir ahold das várias declarações de interface, transated em nossa língua. E estamos presos usando invocações à base de método, ter que especificar todos os parâmetros, por exemplo:.

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

Esta revelou-se, no mundo real, para ter tais desvantagens que estaria disposta a desistir:

  • ligação antecipada
  • código-visão
  • tempo de compilação verificação de sintaxe

e use IDispatch a ligação tardia:

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

Porque automação Excel foi projetado para VB Script, um monte de parâmetros podem ser omitidos, mesmo quando não há sobrecarga sem eles.

Nota: Não confunda o meu exemplo de Excel com uma razão de por que eu quero usar IDispatch. Nem todo objeto COM é Excel. Alguns objetos COM não têm outra do que através de IDispatch apoio.

Foi útil?

Solução

Você pode, relativly, use ligação tardia ligação IDispatch em C #.

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

Aqui estão algumas amostras para usar o Excel. Desta forma, você não precisa adicionar uma dependência desnecessária na PIA bloaty da 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 );

Outras dicas

Você tem que esperar para C # 4.0 para sair para obter a ligação tardia que você está procurando. Toda vez que eu preciso de interoperabilidade capacidades I voltar ao modo VB.Net para que eu possa tirar vantagem das capacidades COM que C # parece falta.

O método simples que eu uso é a criação de uma classe em VB.Net que faz o trabalho IDispatch e, em seguida, expondo os métodos que eu quero usar como métodos de minha capa e então eu posso chamá-los à vontade do meu código C #. Não é o mais elegante de soluções, mas ficou-me sair de uma enrascada ou dois ao longo dos últimos meses.

C # 4 da palavra-chave dynamic suporta IDispatch e ligação tardia. Você pode ler série dinâmica de Sam Ng para mais informações

Oh, e C # 4 está disponível apenas como um CTP hoje. Você vai ter que esperar tanto para o Visual Studio vNext ou usar o beta (que é executado em um Windows Server 2008 Virtual PC) para usá-lo.

provavelmente pode ir longe com muito código mais agradável em em C # 2.0 / 3.0 se você tomar o tempo para escrever uma interface contendo os métodos e propriedades que você quer do objeto e adicionar alguns atributos (i escrevê-lo a partir da memória, por isso detalhes poderão não ser correto, mas eu juro que funcionou para mim ...)

    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 mencionado, o código não vai funcionar fora da caixa, é mais uma dica que a cavar no MSDN.

Como já foi dito - usando c # 4 do "dinâmicos" pedras-chave. Aqui está um exemplo simples - é muito mais sucinta do 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"
}

Ei cara, eu tenho 2 projetos CodePlex atualmente para resolver este problema.

O primeiro é LateBindingApi.Excel http://excel.codeplex.com mapeados latebinded invocar chamada para o modelo de objeto bem conhecido. Este foi um projeto de teste para o seguinte projeto.

o segundo é um CodeGenerator http://latebindingapi.codeplex.com a ferramenta cria c # projetos de bibliotecas COM Tipo. os projetos gerados inclui mapeador de objetos com acesso latebind o servidor COM. O destaque é o libs tipo convertidos ferramenta COM em versões diferentes para um único projeto (por exemplo excel 9,10,11) e marcado todas as entidades com um auto definido SupportByLibrary attribut. Eu analisei todos os aplicativos do Office na versão 9,10,11,12,14 com este esta ferramenta agora e gerar uma solução c #, está disponível como beta testado com código de exemplo na página principal.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top