Как компилятор C# обнаруживает типы COM?



EDIT: я написал результаты как блоге.





компилятор C# обрабатывает типы COM несколько волшебно. Например, это утверждение выглядит нормально...



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


... пока ты не поймешь, что Application - это интерфейс. Вызов конструктора на интерфейсе? Yoiks! Это на самом деле переводится в вызов Type.GetTypeFromCLSID() и другое Activator.CreateInstance.



кроме того, в C# 4 Вы можете использовать аргументы без ссылок для ref параметры, и компилятор просто добавляет локальную переменную для передачи по ссылке, отбрасывая результаты:



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


(Да, есть куча аргументов не хватает. Разве необязательные параметры не хороши? :)



Я пытаюсь исследовать поведение компилятора, и мне не удается подделать первую часть. Я могу сделать вторую часть с проблема:



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);
}
}


Я хотел бы написать:



Dummy dummy = new Dummy();


хотя. Очевидно, что он взорвется во время исполнения, но это нормально. Я просто экспериментирую.



другие атрибуты, добавленные компилятором для связанных com PIAs (CompilerGenerated и TypeIdentifier) не похоже, чтобы сделать трюк... что это за волшебный соус?

661   4  

4 ответов:

ни в коем случае я не эксперт в этом, но я недавно наткнулся на то, что я думаю, что вы хотите:CoClass атрибут class.

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

кокласс поставляет бетон осуществление(ы) одного или нескольких межфазные границы. В COM, такой бетон реализации могут быть написаны на любом язык программирования, поддерживающий COM разработка компонентов, например Delphi, C++, Visual Basic и др.

посмотреть мой ответ на подобный вопрос о Microsoft Speech API, где вы можете "создать экземпляр" интерфейса SpVoice (но на самом деле, вы создаете экземпляр SPVoiceClass).

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

между вами и Майклом вы почти собрали кусочки вместе. Я думаю, что это так работает. (Я не писал код, поэтому я мог бы немного ошибиться, но я уверен, что это так.)

Если:

  • вы "новый" Инг тип интерфейса, и
  • тип интерфейса имеет известный кокласс, и
  • вы используете функцию "нет pia" для этого интерфейса

тогда код генерируется как (IPIAINTERFACE)активатор.CreateInstance (Тип.GetTypeFromClsid (GUID of COCLASSTYPE))

Если:

  • вы "новый" Инг тип интерфейса, и
  • тип интерфейса имеет известный кокласс, и
  • вы не используете функцию "нет pia" для этого интерфейса

затем код генерируется так, как если бы вы сказали "new COCLASSTYPE()".

Джон, не стесняйтесь беспокоить меня или Сэма напрямую, если у вас есть вопросы об этом материале. К ВАШЕМУ СВЕДЕНИЮ, Сэм является экспертом по этой функции.

хорошо, это просто, чтобы положить немного больше плоти на ответ Майкла (он может добавить его, если захочет, и в этом случае я удалю этот).

глядя на оригинальный PIA для Word.Приложение, есть три типа участвующих (игнорируя события):

[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
{
}

есть два интерфейса по причинам, о которых говорит Эрик Липперт в еще один ответ. И там, как вы сказали, находится CoClass - как с точки зрения самого класса и атрибут на Application интерфейс.

теперь, если мы используем PIA linking в C# 4,какой-то это встроено в результирующий двоичный файл... но не все из этого. Приложение, которое просто создает экземпляр Application заканчивается такими типами:

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

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

нет ApplicationClass - предположительно, потому что это будет загружаться динамически из real тип COM во время выполнения.

еще одна интересная вещь-это разница в коде между связанной и несвязанной версиями. Если вы декомпилируете строку

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

на ссылка версия это заканчивается так:

Application application = new ApplicationClass();

а в связан версия это заканчивается как

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

так что похоже, что "настоящий" Пиа нуждается в CoClass атрибут, но связанная версия не делает, потому что там не a CoClass компилятор может фактически ссылаться. Он должен это сделать динамично.

я мог бы попытаться подделать COM-интерфейс, используя эту информацию, и посмотреть, смогу ли я заставить компилятор связать его...

просто чтобы добавить немного подтверждения к ответу Майкла:

следующий код компилируется и работает:

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();
    }
}

нужно ComImportAttribute и GuidAttribute чтобы он работал.

Также обратите внимание на информацию при наведении указателя мыши на new IFoo(): Intellisense правильно подхватывает информацию: приятно!

Comments

    Ничего не найдено.