Как создавать COM+-компоненты на .NET-е (это ответ, а не воп
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.11.02 22:04
Оценка: 163 (25)
#Имя: FAQ.dotnet.complusplus
Всем привет.

Навеяно вот этими топиками:

http://www.rsdn.ru/Forum/?mid=124975
Автор: SCS
Дата: 04.11.02

http://www.rsdn.ru/forum/Message.aspx?mid=125632&only=1
Автор: IT
Дата: 05.11.02

ну и еще многими другими... в общем достали.

Итак почему же столько проблем с COM+-ом если компоненты, и особенно клиента создавать средствами .NET Framework?

По большому счету по двум причинам:

1. Большинство людей пытающихся создавать COM+-компоненты на .NET не указывают (явно) гуидов для всех составляющих будущей библиотеки типв.

2. Люди забывают отключить автоматическое приращение версий сборок в проектах созданных VS.NET.

Итак для того чтобы создать полноценное COM+-приложение нужно:

1. Обявить интерфейс (который в последствии будет использоваться как главный (default) интерфейс ком-объекта) отдельно от описания класса.
2. Задать гуиды для:
* Инерфейса
* Ко-класса (т.е. для класса реализующего ком-объект)
* Сборки (он будет являться LibID)
* AppID

Ниже привдены описания самых важных атрибутов и пример COM+-приложения на Шарпе:

[assembly: Guid("49E484AE-02C4-4c77-A36E-7B4ED0BCE11F")]

Гуид библиотеки типов (LibID)

[assembly: ApplicationActivation(ActivationOption.Server)]

Говорит regsvcs что COM+-приложение нужно регистрировать как серверное, а не как библиотечное (по умолчанию).

[assembly: ApplicationID("49E484AE-02C4-4c77-FFFF-7B4ED0BCE11F")]

ApplicationID в COM+-е. Его можно использовать при отладке.

[assembly: AssemblyDescription("Test AssemblyDescription")]

Превращается в атрибут helpstring в библиотеке типов.

[assembly: ApplicationName("TestNetComPlusServer")]

Имя COM+-приложения.

[assembly: AssemblyVersion("1.1.100.200")]

Версия сборки и по совместительству библиотки типов. В качестве версии библиотеки типов используется первые две цифры. Если клиент нэйтив, используется именно [version(x.x)]. Для .NET-клиентов используется полная версия сборки (!) которая помещается в custom-атрибут с ID == 90883F05-3D28-11D2-8F17-00A0C9A6186D. Например:
[
  uuid(49E484AE-02C4-4C77-A36E-7B4ED0BCE11F),
  version(1.1),
  helpstring("Test AssemblyDescription"),
  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, TestNetComPlusServer, Version=1.1.100.200, Culture=neutral, PublicKeyToken=59079f6e6ca5a503)
]


Это все атрибуты применяемые к сборке.

Здесь ms-help://MS.VSCC/MS.MSDNVS/cpref/html/frlrfsystementerpriseserviceshierarchy.htm (System.EnterpriseServices Hierarchy) можно посмотреть список других атрибутов.

А это пример приложения созданного на Шарепе. В нем можно увидеть применение всех атрибутов и технику описания интерфейса.

[assembly: Guid("49E484AE-02C4-4c77-A36E-7B4ED0BCE11F")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationID("49E484AE-02C4-4c77-FFFF-7B4ED0BCE11F")]
[assembly: AssemblyDescription("Test AssemblyDescription")]
[assembly: ApplicationName("TestNetComPlusServer")]
// Обратите внимание на то, что версия сборки задана явно!
// Т.е. без использования знака *. Это позволяет отучить VS
// излишне беспокоиться о "правильности" версии сборки. 
// И тем самым снять проблему постоянной перерегистрации
// COM+-приложения, COM+-прокси и перекомпиляции клиента.
[assembly: AssemblyVersion("1.1.100.200")]
[assembly: AssemblyDelaySign(false)]
// Строгое имя (а именно так лучше переводить "strong name") 
// нужно создать утилитой Sn.exe
[assembly: AssemblyKeyFile("..\\..\\TestNetComPlusServer.snk")]
[assembly: AssemblyKeyName("")]


using System;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace TestNetComPlusServer
{

    [GuidAttribute("FBEAA7C9-06D2-40a3-A3B7-ABC769DDA589")]
    // Ип интерфейса: Dual, IDispatch или IUnknown
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IServer
    {
        void Method1();
    };

    
    // Переключает галочку "Component supports e&vents and statistics",
    // тем самым позволяя следить за активностью компонента в Component Services
    [EventTrackingEnabledAttribute(true)]
    // CLSID. Сногие думают что так задается IID дефолтного интрфейса, но это не так.
    [Guid("676C8C4F-7178-4023-863F-BC13658B8688")]
    [ClassInterface(ClassInterfaceType.None)]
    // Тут же можно задать кучу дургих атрибутов.
    //[Transaction(TransactionOption.Disabled)]
    public class Server: System.EnterpriseServices.ServicedComponent, IServer
    {
        public Server(){}

        // Лдя методов тоже можно задавать атрибуты.
        //[AutoComplete]
        void IServer.Method1()
        {
            // Метод ком объекта.
            int i = 0;
            i = i;
        }
    }
}



Ниже приведен скрипт регистрирующий приложение в GAC и COM+-е:

cd bin\Debug
gacutil /i TestNetComPlusServer.dll
regsvcs /tlb:TestNetComPlusServer.tlb TestNetComPlusServer.dll


В принципе того же эффекта можно добиться изменением опций проекта.


Вот библиотека типов (реинженирнутая с помощью OLEView) получившаяся после компиляции этого проекта:

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: TestNetComPlusServer.tlb

[
  uuid(49E484AE-02C4-4C77-A36E-7B4ED0BCE11F),
  version(1.1),
  helpstring("Test AssemblyDescription"),
  custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, TestNetComPlusServer, Version=1.1.100.200, Culture=neutral, PublicKeyToken=59079f6e6ca5a503)

]
library TestNetComPlusServer
{
    // TLib :     // TLib : Common Language Runtime Library : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
    importlib("mscorlib.tlb");
    // TLib :  : {4FB2D46F-EFC8-4643-BCD0-6E5BFA6A174C}
    importlib("System.EnterpriseServices.tlb");
    // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");
    // TLib : Common Language Runtime Execution Engine 1.0 Library : {5477469E-83B1-11D2-8B49-00A0C9B7C9C4}
    importlib("mscoree.tlb");

    // Forward declare all types defined in this typelib
    interface IServer;

    [
      odl,
      uuid(FBEAA7C9-06D2-40A3-A3B7-ABC769DDA589),
      version(1.0),
      dual,
      oleautomation,
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, TestNetComPlusServer.IServer)    

    ]
    interface IServer : IDispatch {
        [id(0x60020000)]
        HRESULT Method1();
    };

    [
      uuid(676C8C4F-7178-4023-863F-BC13658B8688),
      version(1.0),
      custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, TestNetComPlusServer.Server)
    ]
    coclass Server {
        interface _Object;
        interface IRemoteDispatch;
        interface IDisposable;
        interface IManagedObject;
        interface System_EnterpriseServices_IServicedComponentInfo;
        [default] interface IServer;
    };
};


Обратите внимание на то, что все гуиды "наши". Они не изменятся ни при перекомпиляции, ни даже при изменении имен интерфейсов.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.