Как компилятор 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 ответов
ни в коем случае я не эксперт в этом, но я недавно наткнулся на то, что, как я думаю, вы хотите:компонентный класс атрибут 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 { }
между вами и Майклом вы почти собрали кусочки вместе. Я думаю, вот как это работает. (Я не писал код, поэтому я могу немного ошибаться, но я уверен, что это так.)
Если:
- вы "новый" ing тип интерфейса, и
- тип интерфейса имеет известный coclass, и
- вы используете функцию "no pia" для этого интерфейса
затем код генерируется как (IPIAINTERFACE)активатор.CreateInstance(Тип.GetTypeFromClsid (GUID COCLASSTYPE))
Если:
- вы "новый" ing тип интерфейса, и
- тип интерфейса имеет известный coclass, и
- вы не используете функцию "no 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
- предположительно, потому что это будет загружаться динамически из реальная тип COM во время выполнения.
еще одна интересная вещь-это разница в коде между связанной и несвязанной версиями. Если вы декомпилируете строку
Word.Application application = new Word.Application();
на ссылка версия он заканчивается как:
Application application = new ApplicationClass();
а в связан версия он заканчивается как
Application application = (Application)
Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));
таким образом, похоже, что "настоящая" PIA нуждается в 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 правильно подбирает информацию: приятно!