Pergunta

EDIT: Eu escrevi os resultados como um blog .


O compilador C # trata COM tipos pouco magicamente. Por exemplo, esta declaração parece normal ...

Word.Application app = new Word.Application();

... até você perceber que Application é uma interface. Chamar um construtor em uma interface? Yoiks! Isso realmente é traduzida em uma chamada para Type.GetTypeFromCLSID() e outra Activator.CreateInstance .

Além disso, em C # 4, você pode usar argumentos não-ref para os parâmetros ref, eo compilador apenas acrescenta uma variável local para passar por referência, descartando os resultados:

// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");

(Sim, há um monte de argumentos em falta não são parâmetros opcionais agradável:.?)

Eu estou tentando investigar o comportamento do compilador, e eu estou deixando de falso a primeira parte. Eu posso fazer a segunda parte sem nenhum 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);
    }
}

Eu gostaria de ser capaz de escrever:

Dummy dummy = new Dummy();

embora. Obviamente, ele vai bater em tempo de execução, mas tudo bem. Eu estou apenas experimentando.

Os outros atributos adicionados pelo compilador para PIAs COM vinculadas (CompilerGenerated e TypeIdentifier) não parecem fazer o truque ... o que é o molho mágico?

Foi útil?

Solução

De maneira nenhuma eu sou um especialista nisso, mas eu tropecei recentemente sobre o que eu acho que você quer: o CoClass classe atributo.

[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }

coclass fornece um concreto execução (s) de um ou mais interfaces. Em COM, tais concreto implementações podem ser escritos em qualquer linguagem de programação que aceita COM desenvolvimento de componentes, por exemplo Delphi, C ++, Visual Basic, etc.

a minha resposta a uma pergunta semelhante sobre a API Microsoft Speech, onde você é capaz de "instanciar" o SpVoice de interface (mas realmente, você está instanciar SPVoiceClass).

[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }

Outras dicas

Entre você e Michael você quase conseguiu os pedaços juntos. Eu acho que isso é como ele funciona. (Eu não escrever o código, então eu poderia ser um pouco mis afirmando-lo, mas eu tenho certeza que isso é como ele vai.)

Se:

  • você é "novo" ing um tipo de interface, e
  • o tipo de interface tem um coclass conhecida, e
  • Você está usando o recurso "não pia" para esta interface

, em seguida, o código é gerado como (IPIAINTERFACE) Activator.CreateInstance (Type.GetTypeFromClsid (GUID DE COCLASSTYPE))

Se:

  • você é "novo" ing um tipo de interface, e
  • o tipo de interface tem um coclass conhecida, e
  • Você não está usando o recurso "não pia" para esta interface

, em seguida, o código é gerado como se você tivesse dito "nova COCLASSTYPE ()".

Jon, fique à vontade para me incomodar ou Sam diretamente se você tiver dúvidas sobre este material. FYI, Sam é o especialista sobre este recurso.

Ok, isso é apenas para colocar um pouco mais de carne sobre a resposta de Michael (bem-vindo ele de adicioná-lo em, se ele quiser, caso em que eu vou remover este).

Olhando para o PIA original para Word.Application, existem três tipos envolvidos (ignorando os eventos):

[ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")]
public interface _Application
{
     ...
}

[ComImport, Guid("..."), CoClass(typeof(ApplicationClass))]
public interface Application : _Application
{
}

[ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."), 
 TypeLibType((short) 2), DefaultMember("Name")]
public class ApplicationClass : _Application, Application
{
}

Existem duas interfaces, por razões que Eric Lippert fala sobre em outra resposta . E lá, como você disse, é o CoClass - tanto em termos da própria classe eo atributo na interface Application

.

Agora, se nós usamos PIA ligando em C # 4, alguns isso está embutido no binário resultante ... mas não toda ela. Uma aplicação que apenas cria uma instância de Application acaba com estes tipos:

[ComImport, TypeIdentifier, Guid("..."), CompilerGenerated]
public interface _Application

[ComImport, Guid("..."), CompilerGenerated, TypeIdentifier]
public interface Application : _Application

No ApplicationClass -. Presumivelmente, porque isso vai ser carregado dinamicamente a partir do real tipo COM em tempo de execução

Outra coisa interessante é a diferença no código entre a versão ligada e a versão não-ligados. Se você decompor a linha

Word.Application application = new Word.Application();

Referenciado versão que acaba como:

Application application = new ApplicationClass();

enquanto que no ligado versão que acaba como

Application application = (Application) 
    Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));

Portanto, parece que o "real" PIA precisa o atributo CoClass, mas a versão ligada não porque há não é a CoClass o compilador pode realmente referência. Tem que fazê-lo de forma dinâmica.

Eu poderia tentar fingir-se de uma interface COM utilizar estas informações e ver se posso obter o compilador para vinculá-lo ...

Só para acrescentar um pouco de confirmação para a resposta de Michael:

Os seguintes compila código e executando o:

public class Program
{
    public class Foo : IFoo
    {
    }

    [Guid("00000000-0000-0000-0000-000000000000")]
    [CoClass(typeof(Foo))]
    [ComImport]
    public interface IFoo
    {
    }

    static void Main(string[] args)
    {
        IFoo foo = new IFoo();
    }
}

Você precisa tanto o ComImportAttribute eo GuidAttribute para que ele funcione.

Além disso, observe as informações quando você passa o mouse sobre a new IFoo(): Intellisense corretamente pega na informação: agradável

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