Почему доступ к COM-объекту из .NET без прохождения через класс Interop иногда работает? - PullRequest
11 голосов
/ 17 июня 2010

Когда вы связываете COM-объект из кода .NET, VS создает DLL взаимодействия с классами взаимодействия.

Пример:

У вас есть foo.dll, который реализует COM-библиотеку Foo, которая включает реализацию COM-интерфейса "IBar". Вы добавляете ссылку на foo.dll в проект .NET. в / bin вы увидите Interop.FooLib.dll. В обозревателе объектов вы увидите Interop.FooLib, под ним вы увидите FooLib, под ним вы увидите BarClass, под которым вы увидите базовые типы, под этим Bar и IBar.

В вашем .NET-коде при объявлении переменной вы можете ввести FooLib, и intellisense предоставит вам опции Bar или BarClass ().

Из того, что я понял, действительно не имеет значения, какой вы используете в объявлении переменной, но очень важно, какой вы использовали для его конструктора.

То есть оба они должны работать:

FooLib.BarClass theBar = new FooLib.BarClass();
FooLib.Bar theBar = new FooLib.BarClass();

Но это не должно работать:

FooLib.Bar theBar = new FooLib.Bar();

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

Итак, кто-нибудь может объяснить, в чем конкретно разница между двумя конструкторами, Bar () и BarClass ()?

Может кто-нибудь объяснить, почему конструктор Bar () иногда работает?

Может ли кто-нибудь предоставить метод, обеспечивающий, чтобы никто не ошибочно вызывал неправильные конструкторы, не читая каждую строку кода?

- ДОБАВЛЕНО -

Было высказано предположение, что проблема была в нашей реализации COM. Вот что мы делаем:

IDL:

[
    object,
    uuid(...),
    dual,
    helpstring("IBar Interface"),
    pointer_default(unique),
    nonextensible
]
interface IBar : IDispatch
{
    [id(1), helpstring("method barify")] 
        HRESULT barify([out, retval] VARIANT_BOOL *rVal);
    // ...
};
// ...
[
    uuid(...),
    version(1.0),
    helpstring("Foo 1.0 Type Library")
]
library FooLib
{
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    // ...
    [
        uuid(...),
        helpstring("Bar Class")
    ]
    coclass Bar
    {
        [default] interface IBar;
    };
    // ...
};

Реализация:

class ATL_NO_VTABLE CBar : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CBar, &CLSID_Bar>,
    public IDispatchImpl<IBar, &IID_IBar, &LIBID_FooLib>,
    public ISupportErrorInfoImpl <&IID_IBar>
{
public:
    CBar();

    DECLARE_REGISTRY_RESOURCEID(IDR_BAR)

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    BEGIN_COM_MAP(CBar)
        COM_INTERFACE_ENTRY(IBar)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(ISupportErrorInfo)
    END_COM_MAP()

    // ...
};

- ДОБАВЛЕНО ПОЗЖЕ -

Декомпилировать *, через .NET Reflector:

[ComImport, CoClass(typeof(BarClass)), Guid("...")]
public interface Bar : IBar
{
}

* Мне все равно, что пользовательский интерфейс Reflector называет это дизассемблированием - если он выводит HLL, это декомпиляция.

Ответы [ 3 ]

2 голосов
/ 17 июня 2010

Отличный вопрос.Многие удивляются, что это работает вообще, потому что Bar - это интерфейс, и, конечно же, вы не сможете создать новый экземпляр интерфейса!Но хотя я не могу найти какой-либо специфики реализации, я помню, как читал в книге взаимодействия Адама Натана по COM, что C # делает специальное исключение для интерфейсов COM, помеченных CoClassAttribute, и вместо этого превращает вызов в экземпляр экземпляра класса.1001 *

Но я не знаю, почему это иногда работает, а иногда не работает.

0 голосов
/ 18 июня 2010

Читали ли вы обсуждение в этот вопрос ?Это обсуждает именно эту проблему, я думаю.

0 голосов
/ 17 июня 2010

Конструктор Bar () в принципе должен явно возвращать интерфейс вместо объекта класса. Я не могу понять, как .NET поддерживает создание интерфейса !?

В любом случае, вы можете нажать на конструктор Bar () и нажать Shift-F12. Это покажет вам где-нибудь еще в коде, где этот конструктор используется. Я не могу придумать, как предотвратить случайный вызов этого конструктора пользователем.

...