Как компилятор 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) не похоже, чтобы сделать трюк... что это за волшебный соус?
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атрибут, но связанная версия не делает, потому что там не aCoClassкомпилятор может фактически ссылаться. Он должен это сделать динамично.я мог бы попытаться подделать 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