Вопрос

РЕДАКТИРОВАТЬ: Я записал результаты в виде Сообщение блога.


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

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

...пока ты не поймешь это Application это интерфейс.Вызов конструктора интерфейса?Йойкс!Фактически это преобразуется в вызов 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 PIA (CompilerGenerated и TypeIdentifier) похоже, не помогает...что за волшебный соус?

Это было полезно?

Решение

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

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

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

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

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

Другие советы

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

Если:

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

тогда код генерируется как (IPIAINTERFACE)Activator.CreateInstance(Type.GetTypeFromClsid(GUID OF COCLASSTYPE))

Если:

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

тогда код генерируется так, как если бы вы сказали «новый COCLASSTYPE()».

Джон, не стесняйся обращаться ко мне или Сэму напрямую, если у тебя есть вопросы по этому поводу.К вашему сведению, Сэм — эксперт по этой функции.

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

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

[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 в 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 атрибут, но в связанной версии его нет, потому что там не а 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 правильно воспринимает информацию:Хороший!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top