Сообщений 6    Оценка 15 [+1/-4]         Оценить  
Система Orphus

Q&A: Компоненты COM+ средствами .NET Framework

Автор: Владислав Чистяков (VladD2)
The RSDN Group

Источник: RSDN Magazine #3-2004
Опубликовано: 05.08.2004
Исправлено: 10.12.2016
Версия текста: 1.0

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

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

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

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

  1. Объявить интерфейс (который впоследствии будет использоваться как главный (default) интерфейс ком-объекта) отдельно от описания класса.
  2. Задать GUID-ы для:

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

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

GUID библиотеки типов (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")]

Версия сборки и, по совместительству, библиотеки типов. В качестве версии библиотеки типов используются первые две цифры. В случае native-клиента используется именно [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)
]

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

Здесь - 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)]
  publicinterface IServer
  {
    void Method1();
  };

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

    // Для методов тоже можно задавать атрибуты.//[AutoComplete]void IServer.Method1()
    {
      // Метод COM-объекта.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 typelibinterface 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 Magazine #3-2004. Информацию о журнале можно найти здесь
    Сообщений 6    Оценка 15 [+1/-4]         Оценить