При взаимодействии через интерфейс с COM-объектом из кода.NET VS создает interop DLL с interop классами.
Пример:
У Вас есть foo.dll реализации Нечто библиотеки COM, которое включает реализацию COM-интерфейса "IBar". Вы добавляете ссылку на foo.dll к проекту.NET. в / мусорном ведре Вы будете видеть Interop.FooLib.dll. В Обозревателе объектов Вы будете видеть Interop. FooLib, под которым Вы будете видеть FooLib, под которым Вы будете видеть BarClass, под которым Вы будете видеть Базовые типы под той Панелью и IBar.
В Вашем коде.NET, при объявлении переменной, можно ввести FooLib, и intellisense даст Вам опции или Панели или BarClass ().
Из того, что я понял, это действительно не имеет значения, который Вы используете в объявлении переменной, но это очень имеет значение, который Вы использовали для его конструктора.
Таким образом, оба из них должны работать:
FooLib.BarClass theBar = new FooLib.BarClass();
FooLib.Bar theBar = new FooLib.BarClass();
Но это не должно работать:
FooLib.Bar theBar = new FooLib.Bar();
Вот проблема. Мы просто разыскали нечетную ошибку, где код, который работал на некоторых клиентов, и работал в наших средах разработки и тестовых средах, не работал на одном сайте для клиентов, выпущенном, чтобы быть программистом, использующим Панель () конструктор.
Так, кто-либо может объяснить точно, что различие между этими двумя конструкторами, Панель (), и BarClass ()?
Кто-либо может объяснить, почему Панель () конструктор, кажется, работает, иногда?
Кто-либо может предоставить метод для обеспечения, что никто по ошибке не вызывает неправильных конструкторов, не читая каждую строку кода?
- ДОБАВЛЕННЫЙ-
Было предложено, чтобы проблема была в нашей реализации 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:
[ComImport, CoClass(typeof(BarClass)), Guid("...")]
public interface Bar : IBar
{
}
*Я не забочусь, что Отражатель, UI называет это дизассемблированием - если это производит HLL, это - декомпиляция.
Отличный вопрос. Многие люди удивлены, что это вообще работает, потому что Bar - это интерфейс, и вы, конечно же, не сможете создать новый экземпляр интерфейса! Но хотя я не могу найти каких-либо особенностей реализации, я помню, как читал в книге Адама Натана по COM-взаимодействию, что C # делает специальное исключение для COM-интерфейсов, помеченных CoClassAttribute, и вместо этого превращает вызов в экземпляр кокласса.
Но я не знаю, почему это иногда срабатывает, а иногда нет.
Читали ли вы обсуждение в этом вопросе? Там обсуждается именно этот вопрос, я думаю.
Конструктор Bar () в принципе должен явно возвращать интерфейс, а не объект класса. Я не могу понять, как .NET поддерживает создание интерфейса !?
В любом случае вы можете щелкнуть конструктор Bar () и нажать Shift-F12. Это покажет вам где-нибудь еще в коде, где используется этот конструктор. Я не могу придумать способ предотвратить случайный вызов этого конструктора пользователем.