Does C # .NET suporte IDispatch ligação tardia?
-
03-07-2019 - |
Pergunta
A Pergunta ??h2>
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.
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.