Как создавать 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 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.11.02 06:58
Оценка: 18 (1)
Здравствуйте IT, Вы писали:

IT>Я не нашёл, хотя перерыл всё. Правда дело было ещё до релиза и может этого тогда ещё не было в документации (а может и в природе),


Я про это не в документации нашел а сам догадался. Там правда никакого COM+ не было, но эта коза цеплялась к конкретной версии библиотеки, а так как при перекомпиляции она менялась то студия продолжала цеплять старый вариант.
... << RSDN@Home 1.0 alpha 12 (developers build)>>
AVK Blog
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.03 21:10
Оценка: +1
Здравствуйте, mihailik, Вы писали:

M>А не прояснишь ещё, как взаимоотносятся концепции наследования интерфейсов в COM и .NET?


Я уже плюнул на КОМ. Так что не хочется даже разбираться...

M>Может вообще нужно избегать наследования интерфейсов в .NET-компонентах, которые будут использоваться в COM/COM+?


Я и в КОМ этим не пользовался. Куда проще и гибче реализовать два интерфейса.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.11.02 22:19
Оценка:
Здравствуйте VladD2, Вы писали:


Да! Совсем забыл. Вот код нетного клиента. Это тоже не маловажно...

// Получаем тип ком-объекта из его CLSID...
Type type = Type.GetTypeFromCLSID(
new Guid("676C8C4F-7178-4023-863F-BC13658B8688"),
"STAS");

// Создаем экземпляр...
IServer srv = (IServer)Activator.CreateInstance(type);

MessageBox.Show("OK TestNetComPlusServer.Server new");
srv.Method1(); // вызываем метод...
MessageBox.Show("OK Method1");
// Если нужно освободить ссвлку вызываем:
ServicedComponent.DisposeObject((ServicedComponent)srv);
// Иначе экземпляр объекта будет болтаться до сборки мусора.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.11.02 22:20
Оценка:
Здравствуйте VladD2, Вы писали:

Елы-палы... Ладно... еще раз в цвете.

Здравствуйте VladD2, Вы писали:

Да! Совсем забыл. Вот код нетного клиента. Это тоже не маловажно...
// Получаем тип ком-объекта из его CLSID... 
Type type = Type.GetTypeFromCLSID( 
   new Guid("676C8C4F-7178-4023-863F-BC13658B8688"), 
   "STAS"); 

// Создаем экземпляр... 
IServer srv = (IServer)Activator.CreateInstance(type); 

MessageBox.Show("OK TestNetComPlusServer.Server new"); 
srv.Method1(); // вызываем метод... 
MessageBox.Show("OK Method1"); 
// Если нужно освободить ссвлку вызываем: 
ServicedComponent.DisposeObject((ServicedComponent)srv); 
// Иначе экземпляр объекта будет болтаться до сборки мусора.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: IT Россия linq2db.com
Дата: 06.11.02 22:38
Оценка:
Здравствуйте VladD2, Вы писали:

VD>// Обратите внимание на то, что версия сборки задана явно!
VD>// Т.е. без использования знака *. Это позволяет отучить VS
VD>// излишне беспокоиться о "правильности" версии сборки. 
VD>// И тем самым снять проблему постоянной перерегистрации
VD>// COM+-приложения, COM+-прокси и перекомпиляции клиента.


Вот за это мы молодец. Только скажи, где ты это нашёл?
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.11.02 23:46
Оценка:
Здравствуйте IT, Вы писали:

IT>
VD>>// Обратите внимание на то, что версия сборки задана явно!
VD>>// Т.е. без использования знака *. Это позволяет отучить VS
VD>>// излишне беспокоиться о "правильности" версии сборки. 
VD>>// И тем самым снять проблему постоянной перерегистрации
VD>>// COM+-приложения, COM+-прокси и перекомпиляции клиента.
IT>


IT>Вот за это мы молодец. Только скажи, где ты это нашёл?


AVK так затрахался с моим TreeView что что-то там нахимичил и VS стала плевать на версии сборки. Ну я полез MSDN и в VS.NET и нарыл. То или нет не знаю, но работает.

А что за [assembly: Guid("49E484AE-02C4-4c77-A36E-7B4ED0BCE11F")] я не моледец?
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: IT Россия linq2db.com
Дата: 07.11.02 01:18
Оценка:
Здравствуйте VladD2, Вы писали:

IT>>Вот за это мы молодец. Только скажи, где ты это нашёл?


VD>AVK так затрахался с моим TreeView что что-то там нахимичил и VS стала плевать на версии сборки. Ну я полез MSDN и в VS.NET и нарыл. То или нет не знаю, но работает.


Я не нашёл, хотя перерыл всё. Правда дело было ещё до релиза и может этого тогда ещё не было в документации (а может и в природе),

VD>А что за [assembly: Guid("49E484AE-02C4-4c77-A36E-7B4ED0BCE11F")] я не моледец?


То же молодец, но это я возможно пробовал (опять же, если оно было).

Короче, всё это здорово, но ком всё равно уже пора хоронить
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 01:52
Оценка:
Здравствуйте IT, Вы писали:

IT>Короче, всё это здорово, но ком всё равно уже пора хоронить


Тады пиши в MS писмо с просьбой сделать сервер приложений под ремоутинг. А то самопальные экзешники супратив КОМ+ — это не серьезно.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: IT Россия linq2db.com
Дата: 07.11.02 03:16
Оценка:
Здравствуйте VladD2, Вы писали:

IT>>Короче, всё это здорово, но ком всё равно уже пора хоронить


VD>Тады пиши в MS писмо с просьбой сделать сервер приложений под ремоутинг. А то самопальные экзешники супратив КОМ+ — это не серьезно.


Со мной работает чел у которого brother-in-law колбасит CLR в Редмонде. Я попросил его по секрету выведать как с этим в MS обстоит дело Скоро узнаем.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: retalik www.airbandits.com/
Дата: 07.11.02 05:09
Оценка:
Здравствуйте IT, Вы писали:
IT>Со мной работает чел у которого brother-in-law колбасит CLR в Редмонде. Я попросил его по секрету выведать как с этим в MS обстоит дело Скоро узнаем.
По секрету? Это хорошо. А на форуме расскажешь?
Успехов,
Виталий.
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: zelyony  
Дата: 07.11.02 05:37
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Здравствуйте VladD2, Вы писали:


VD>Да! Совсем забыл. Вот код нетного клиента. Это тоже не маловажно...

VD>
VD>// Получаем тип ком-объекта из его CLSID... 
VD>Type type = Type.GetTypeFromCLSID( 
VD>   new Guid("676C8C4F-7178-4023-863F-BC13658B8688"), 
VD>   "STAS"); 

VD>// Создаем экземпляр... 
VD>IServer srv = (IServer)Activator.CreateInstance(type); 

VD>MessageBox.Show("OK TestNetComPlusServer.Server new"); 
VD>srv.Method1(); // вызываем метод... 
VD>MessageBox.Show("OK Method1"); 
VD>// Если нужно освободить ссвлку вызываем: 
VD>ServicedComponent.DisposeObject((ServicedComponent)srv); 
VD>// Иначе экземпляр объекта будет болтаться до сборки мусора. 
VD>


это всё хорошо и свойства и методы для кокласса работают
но как только вводим косвенность(метод или свойство кокласса возвращает другой объект или интерфейс), то работать с полученным объектом не получается:
то ему сериализация(которая для СОМ-объектов не нужна), то ему RemotingException(СОМ не работает через ремотинг)...
VladD2, если у тебя всё же получается, то не мог бы написать примерчик или подредактировать этот здесь
Автор:
Дата: 01.11.02
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: dragon23 Россия none
Дата: 07.11.02 07:21
Оценка:
Здравствуйте VladD2, Вы писали:

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


Интерфейс отдельно можно и не объявлять, пусть c# сам поработает и если вы не завели новые public методы, свойства и т.п., т.е. не расширили интерфейс, то будет работать без перерегистрации.

Например,так

[ClassInterface(ClassInterfaceType.AutoDual)]


VD>// Обратите внимание на то, что версия сборки задана явно!

VD>// Т.е. без использования знака *. Это позволяет отучить VS
VD>// излишне беспокоиться о "правильности" версии сборки.
VD>// И тем самым снять проблему постоянной перерегистрации
VD>// COM+-приложения, COM+-прокси и перекомпиляции клиента.
VD>[assembly: AssemblyVersion("1.1.100.200")]

Так вот с этой строчкой работает ничуть не хуже

[assembly: AssemblyVersion("1.1.*")]


и не требуется ни какой перерегистрации приложения или перекомпиляции клиента
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 12:19
Оценка:
Здравствуйте dragon23, Вы писали:

D>Интерфейс отдельно можно и не объявлять, пусть c# сам поработает и если вы не завели новые public методы, свойства и т.п., т.е. не расширили интерфейс, то будет работать без перерегистрации.


D>Например,так


D>
D>[ClassInterface(ClassInterfaceType.AutoDual)]
D>


Нельзя. Есле не ребилд, то покрайней мере банальное добавление метода приведет к тому, что для интерфейса будет сгенерирован новый гуид. Это приведет к неработоспособности половины клиентов. Остальных придется перекомпилировать. Единственный разумный выход — это отдельное описание интерфейса и задание ему гуида вручную.

Более того. Это еще и более коректно с точки зрения качества описания интерфейса между клиентом и сервером. Всегда лучше чтобы паблик-интерфейс передающийся на сервер был описан отдельно и его методы не пересикались с методами реализации. Вдруг придется вызывать этот объект не как COM-сервер, т.е. через его паблик-методы или через другой интерфейс?

VD>>// Обратите внимание на то, что версия сборки задана явно!

VD>>// Т.е. без использования знака *. Это позволяет отучить VS
VD>>// излишне беспокоиться о "правильности" версии сборки.
VD>>// И тем самым снять проблему постоянной перерегистрации
VD>>// COM+-приложения, COM+-прокси и перекомпиляции клиента.
VD>>[assembly: AssemblyVersion("1.1.100.200")]

D>Так вот с этой строчкой работает ничуть не хуже


D>
D>[assembly: AssemblyVersion("1.1.*")]
D>


D>и не требуется ни какой перерегистрации приложения или перекомпиляции клиента


Ну ты попробуй. Создай клиента на .NET... зарегистрируй его на удаленном компьютере... перекомпилируй сервер... далее ты все поймешь, ты все увидишь сам.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 12:24
Оценка:
Здравствуйте zelyony, Вы писали:

Z>это всё хорошо и свойства и методы для кокласса работают

Z>но как только вводим косвенность(метод или свойство кокласса возвращает другой объект или интерфейс), то работать с полученным объектом не получается:
Z>то ему сериализация(которая для СОМ-объектов не нужна), то ему RemotingException(СОМ не работает через ремотинг)...
Z>VladD2, если у тебя всё же получается, то не мог бы написать примерчик или подредактировать этот здесь
Автор:
Дата: 01.11.02


Датасет пробывал передавать. Но это .NET-ый объект. Ладно позже попробую покапать в области передачи объектов.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: dragon23 Россия none
Дата: 07.11.02 12:34
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Нельзя. Есле не ребилд, то покрайней мере банальное добавление метода приведет к тому, что для интерфейса будет сгенерирован новый гуид. Это приведет к неработоспособности половины клиентов. Остальных придется перекомпилировать. Единственный разумный выход — это отдельное описание интерфейса и задание ему гуида вручную.


Никто не мешает задать тот же самый guid и для класса и тогда изменение ничего за собой не повлечет, а чтобы интерфейс не менялся не стоит методы, свойства и т.п. делать public.

VD>Ну ты попробуй. Создай клиента на .NET... зарегистрируй его на удаленном компьютере... перекомпилируй сервер... далее ты все поймешь, ты все увидишь сам.


Насчет .Net клиента не знаю не пробовал, а клиенты на Cpp и Delphi работают и не замечают какая версия.
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 13:02
Оценка:
Здравствуйте dragon23, Вы писали:

D>Никто не мешает задать тот же самый guid и для класса


Что значит тот же самый? Ты задаеш гуид исключительно для класа, т.е. ты задаешь исключительно CLSID. Гуид интерфейса при этом задать невозможно!

D>и тогда изменение ничего за собой не повлечет,


Первый же клиент пытающийся без перекомпиляции сделать QI будет послан к ... Причем тебе придется перерегистрировать приложение в COM+-е, переделывать прокси и перекомпилировать клиента. Как показывает практика если эти действия не автоматизированы, получается форменное шаманство с непредсказуемым результатом.

D>а чтобы интерфейс не менялся не стоит методы, свойства и т.п. делать public.


Это диктуется логикой работы приложения. Иногда без этог не обойтись. Более того интерфейс в процессе разработки принципиально изменяется. Обычно при этом всего лишь добавляются методы. И явное прописывание гуидов является самым просты способом избежать шаманства.

VD>>Ну ты попробуй. Создай клиента на .NET... зарегистрируй его на удаленном компьютере... перекомпилируй сервер... далее ты все поймешь, ты все увидишь сам.


D>Насчет .Net клиента не знаю не пробовал, ...


Не завешь, а говоришь. Мы не просто так извращались. Была реальная проблема... Даже обычная перекомпиляция приводила к неработоспособности клиента. Я не знаю точно кто тому виной, но так она решается.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: IT Россия linq2db.com
Дата: 07.11.02 14:29
Оценка:
Здравствуйте AndrewVK, Вы писали:

IT>>Я не нашёл, хотя перерыл всё. Правда дело было ещё до релиза и может этого тогда ещё не было в документации (а может и в природе),


AVK>Я про это не в документации нашел а сам догадался. Там правда никакого COM+ не было, но эта коза цеплялась к конкретной версии библиотеки, а так как при перекомпиляции она менялась то студия продолжала цеплять старый вариант.


Значит это всё не документировано, т.е. почти хак. И после этого этот злобный Влад обвиняет меня в невнимательности при чтении документации и предвзятому отношению к веб-сервисам. как жить дальше.
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.11.02 14:32
Оценка:
Здравствуйте IT, Вы писали:

IT>Значит это всё не документировано, т.е. почти хак.


Это не хак, это глюк.
... << RSDN@Home 1.0 alpha 12 (developers build)>>
AVK Blog
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 17:24
Оценка:
Здравствуйте IT, Вы писали:

AVK>>Я про это не в документации нашел а сам догадался. Там правда никакого COM+ не было, но эта коза цеплялась к конкретной версии библиотеки, а так как при перекомпиляции она менялась то студия продолжала цеплять старый вариант.


IT>Значит это всё не документировано, т.е. почти хак. И после этого этот злобный Влад обвиняет меня в невнимательности при чтении документации и предвзятому отношению к веб-сервисам. как жить дальше.


Вообще-то если вызвать хелп на AssemblyVersion, то там все более менее объясняется. Догатдаться нужно только о том, что в референсе запоминается полный номер сборки. Но это вроде не сложно.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: TK Лес кывт.рф
Дата: 07.11.02 17:30
Оценка:
Здравствуйте AndrewVK, Вы писали:

AVK>Здравствуйте IT, Вы писали:


IT>>Я не нашёл, хотя перерыл всё. Правда дело было ещё до релиза и может этого тогда ещё не было в документации (а может и в природе),


AVK>Я про это не в документации нашел а сам догадался. Там правда никакого COM+ не было, но эта коза цеплялась к конкретной версии библиотеки, а так как при перекомпиляции она менялась то студия продолжала цеплять старый вариант.


Странное поведение. Не разу с подобным не встречался. Если все проекты в рамках одного solution, то студия нормально перестраивает все ссылки.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.11.02 17:52
Оценка:
Здравствуйте TK, Вы писали:

TK>Странное поведение. Не разу с подобным не встречался. Если все проекты в рамках одного solution, то студия нормально перестраивает все ссылки.


А ты попробуй часть на МС++ написать — сразу столкнешся
... << RSDN@Home 1.0 alpha 12 (developers build)>>
AVK Blog
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 17:54
Оценка:
Здравствуйте zelyony, Вы писали:

Z>это всё хорошо и свойства и методы для кокласса работают

Z>но как только вводим косвенность(метод или свойство кокласса возвращает другой объект или интерфейс), то работать с полученным объектом не получается:
Z>то ему сериализация(которая для СОМ-объектов не нужна), то ему RemotingException(СОМ не работает через ремотинг)...
Z>VladD2, если у тебя всё же получается, то не мог бы написать примерчик или подредактировать этот здесь
Автор:
Дата: 01.11.02


Вот только что попробывал. Все кроме обработки событий работает нормально. События тоже реализуются, но вот как их вызвать? Так как описано в документации не получается, так как одним из пунктов там идет импорт библиотеки типров, но ведь при попытке импорта говорят, что мол эта сборка экспортирована из нэта и, мол, нефига ее еще раз импортировать. Пользуйтес, мол, исходной сборкой.

Пример лежит здесь ftp://rsdn.ru/pubs/temp/Net/COMplus.zip

Запускать нужно солюшен TestNetComPlusServer.

Там создано два объекта один из которых возвращается через метод второго:
        IRetClass IServer.GetRes()
        {
            return new RetClass();
        }


Сам второй объект обявлен так:
    [Guid("42E77602-F139-42f0-B76A-646083DEFC4F")]
    public delegate void TestEventDelegate(ref int iTest);

    [Guid("6836E9CD-4E6E-40e9-936A-FA0CB7829A63") ]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IRetClassEvents
    {
        [DispId(1)]
        void TestEvent(ref int iTest);
    }


    [Guid("C00695BD-6708-44cf-8AFE-249C8C98D3C8")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IRetClass
    {
        int Method1();
        void Fire();
    };

    /// <summary>
    /// Summary description for RetClass.
    /// </summary>
    [EventTrackingEnabled(true)]
    [Guid("055E3D43-933F-46a3-8A85-66F86D603ADC")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IRetClassEvents)/*"TestNetComPlusServer.IRetClassEvents"*/)]
    public class RetClass : System.EnterpriseServices.ServicedComponent, IRetClass
    {
        public event TestEventDelegate TestEvent;

        public RetClass(){}
        int IRetClass.Method1()
        {
            return -1;
        }
        void IRetClass.Fire()
        {
            int i = 10;
            if(TestEvent != null)
                TestEvent(ref i);
            MessageBox.Show("iTest = " + i.ToString(), "COM+-сервер!");            
        }
    }


В общем с точки зрения возврата ссылки на объект все впорядке.

Что же касается событий. То тут или я не понял или это действительно труба. То как делал ты (объявление делегатов внутри интерфейса — это явно неверно, так как при этом делегаты првращаются в тпы КОМ-а и работа ведется не через конекшон поинт, а черт знает как) делать не нужно.

В принципе события через конекшон-поинт в КОМ-объектах — это зло! Так как сервер становится зависимым от клиента. Пути обхода следующие:
* Использовать quied-компоненты из COM+.
* Использовать MSMQ.
* Вручную реализовать конекшон-поинт и нужный событийный интерфейс. (это если уж очень охото сделать именно через конекшон поинт)
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 17:58
Оценка:
Здравствуйте AndrewVK, Вы писали:

TK>>Странное поведение. Не разу с подобным не встречался. Если все проекты в рамках одного solution, то студия нормально перестраивает все ссылки.


AVK>А ты попробуй часть на МС++ написать — сразу столкнешся


Похоже с комплюсом та же песня.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: TK Лес кывт.рф
Дата: 07.11.02 19:27
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Здравствуйте AndrewVK, Вы писали:


TK>>>Странное поведение. Не разу с подобным не встречался. Если все проекты в рамках одного solution, то студия нормально перестраивает все ссылки.


AVK>>А ты попробуй часть на МС++ написать — сразу столкнешся


VD>Похоже с комплюсом та же песня.


Не знаю про что эта пести, но я ее не слышу...
Такого, что-бы один проект в solution изменился, а другие этих изменений не увидили — такого не разу не видел.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[9]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 20:05
Оценка:
Здравствуйте TK, Вы писали:

TK>Не знаю про что эта пести, но я ее не слышу...

TK>Такого, что-бы один проект в solution изменился, а другие этих изменений не увидили — такого не разу не видел.

Займись комплюсом или МС++ и увидишь. В МС++ чистый баг. В КОМ+-е между клиентом и серывером прокси. По идее пока интерфес не изменился можно пользоваться старой прокси и старым клиентом. Но в .NET глюк. При любой перекомпиляции проекта клиент (если он Нэтный) перестает работать. Если не выбросить * из версии сборки, то так и будешь перекомпилировать и перерегистрировать все каждый раз.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Как создавать COM+-компоненты на .NET-е (это ответ,
От: TK Лес кывт.рф
Дата: 07.11.02 20:49
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Здравствуйте TK, Вы писали:


TK>>Не знаю про что эта пести, но я ее не слышу...

TK>>Такого, что-бы один проект в solution изменился, а другие этих изменений не увидили — такого не разу не видел.

VD>Займись комплюсом или МС++ и увидишь. В МС++ чистый баг. В КОМ+-е между клиентом и серывером прокси. По идее пока интерфес не изменился можно пользоваться старой прокси и старым клиентом. Но в .NET глюк. При любой перекомпиляции проекта клиент (если он Нэтный) перестает работать. Если не выбросить * из версии сборки, то так и будешь перекомпилировать и перерегистрировать все каждый раз.


Для COM+ с подобным можно столкнуться если только в ASP.NET в остальных случаях обычно хватает прав,
что-бы сборка автоматически зарегистрировалась как COM+ приложение. В целом — не сказать, что не удобств очень много. Единственное, с чем столкнулся — серверное COM+ приложение. есть метод с enum аргументом и если сборка не в GAC, то клиент метод с этим enum не видит....
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[11]: Как создавать COM+-компоненты на .NET-е (это ответ,
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.11.02 22:38
Оценка:
Здравствуйте TK, Вы писали:

TK>Для COM+ с подобным можно столкнуться если только в ASP.NET в остальных случаях обычно хватает прав,

TK>что-бы сборка автоматически зарегистрировалась как COM+ приложение. В целом — не сказать, что не удобств очень много. Единственное, с чем столкнулся — серверное COM+ приложение. есть метод с enum аргументом и если сборка не в GAC, то клиент метод с этим enum не видит....

Ну тебе виднее. У всех проблемы есть, а у тебя нет.
... << RSDN@Home 1.0 alpha VladD2.1.0.alpha 12.1.0.1028.36665 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: SCS  
Дата: 09.11.02 09:51
Оценка:
Здравствуйте VladD2, Вы писали:
VD>Вот только что попробывал. Все кроме обработки событий работает нормально. События тоже реализуются, но вот как их вызвать? Так как описано в документации не получается, так как одним из пунктов там идет импорт библиотеки типров, но ведь при попытке импорта говорят, что мол эта сборка экспортирована из нэта и, мол, нефига ее еще раз импортировать. Пользуйтес, мол, исходной сборкой.


Пример .Net клиента с "косвенностью" и событиями и COM+ сервера LCE
Пример лежит здесь ftp://rsdn.ru/pubs/temp/Net/COMEvent.zip
SCS
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: zelyony  
Дата: 09.11.02 18:54
Оценка:
в общем, благодаря VladD2, понял следующее:

1) ВСЕ КОКЛАССЫ должны пораждаться от ServisedComponent
тогда они работают как и должны
а я не все коклассы порождал... поэтому порождались баги

2) эвенты в виде делегатов я тоже заставить работать не смог
а вот подписку к интерфейсам и отписку реализовал через IConnectionPointContainer
работает как надо
НО если забыть отписаться и закрыть приложение, следующим и будущим стокам будет кирдык
(но это в СОМе повсеместно, даже через __raise, только если сам в сервере пробегаешь по стокам и выкидываешь те, что отрубились, а те, что выбросили исключения или вернули фиговый HRESULT — игнорируешь)
а идея на этот счёт простая(для .NET, там ведь через делегаты):
у нас есть код: если такой-то эвент не null, то вызываем его с параметрами
но эвент это delegate, т.е потомок Delegate
поэтому, побегаем по каждому .GetInvocationList() и вызываем какждый коннекш по отдельности
если выкинутое исключение относится к ("типа!") "RPC сервер не доступен" — значит клиент отрубился и его можно выкинуть из списка данного delegate

то, что выше должно быть понятно тем, кто "работал" с этим делом
для тех, кому примеры понятнее вот работающие классы:
!!! знатоки подскажите на счёт ссылок в файле EventsCOM(там стоят "//???????") — to be or not to be (я про Release)

СОМ+ сервер Simple.cs ( делаете libarary, кидаете в ГАК и regsvcs )
#define DEBUG

using System;
using System.Net;
using System.Reflection;
using System.Diagnostics;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

[assembly: AssemblyKeyFile("simple.snk")]
[assembly: ApplicationName("simple COM+ C# application with events")]
[assembly: ApplicationID("20b18415-7ece-4658-8581-368dc51f3dfb")]
[assembly: ApplicationActivation(ActivationOption.Server)]
[   
    assembly: ApplicationAccessControl( false,
        AccessChecksLevel=AccessChecksLevelOption.Application,
        Authentication=AuthenticationOption.None,
        ImpersonationLevel=ImpersonationLevelOption.Identify
    )
]

namespace SimpleApp {

    [Guid("f72941f4-57fa-46db-89ba-df4a17277b05")]
    public delegate void OnInfoDelegate( string info );

    [Guid("ba68ccff-f87e-41a0-bec3-6d7f17315e59")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ISimpleEvents {
        [DispId(1)]
        void OnInfoCB(string info);
    }

    [Guid("b680512f-c230-4b44-8768-4a247e6def7a")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ISimpleEvents2 {
        [DispId(1)]
        void OnInfoCB2(string info);
    }

    [Guid("92666404-44c0-4236-a686-94936872625f")]
    public interface ISimple {

        String Info { get; }

        void Fire( int i );
        
    }

    [ComSourceInterfaces(typeof(SimpleApp.ISimpleEvents), typeof(SimpleApp.ISimpleEvents2))]
//    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("df3a3ea6-692a-4f01-a8a4-4f7b85bc2490")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Simple : ServicedComponent, ISimple {

        private static int 
            s_instanceId = 0;
        private int
            m_instanceId;

        public event OnInfoDelegate 
            OnInfoCB, 
            OnInfoCB2;

        public Simple() {
            m_instanceId = ++s_instanceId; 
            Debug.WriteLine( String.Format("Simple.Simple() // m_instanceId={0}", m_instanceId) );
        }

        public String Info {
            get {
                Object[] os = 
                { 
                    Dns.GetHostName(), 
                    m_instanceId, 
                    GetCurrentProcessId(),
                    GetCurrentThreadId(),
                    DateTime.Now
                };
                return String.Format( "machine = \"{0}\"\ninstance = {1}\nprocess = {2}\nthread = {3}\ntime = \"{4}\"", os );
            }
        }

        public void Fire( int cnt ) {
            Debug.WriteLine( String.Format("Simple.Fire( {0} )", cnt) );
            for (int i=0; i<cnt; ++i ) FireEvent();
        }

        private void FireEvent() {
            if ((OnInfoCB!=null) || (OnInfoCB2!=null)) {
                Object[] os = 
                { 
                    Dns.GetHostName(), 
                    m_instanceId, 
                    GetCurrentProcessId(),
                    GetCurrentThreadId(),
                    DateTime.Now
                };
                string s = String.Format( "machine = \"{0}\"\ninstance = {1}\nprocess = {2}\nthread = {3}\ntime = \"{4}\"", os );
                Debug.WriteLine( "Simple.FireEvent() // info=\"{0}\"", s.Replace("\n", "\n=>") );
                if (OnInfoCB!=null) OnInfoCB(s);
                if (OnInfoCB2!=null) OnInfoCB2(s); 
            }
        }

        [DllImport("Kernel32.dll"), PreserveSig]
        internal static extern int GetCurrentProcessId();
    
        [DllImport("Kernel32.dll"), PreserveSig]
        internal static extern int GetCurrentThreadId();
    }

    [Guid("52c9ef16-ab5c-4b5c-a8de-e0092b314997")]
    public interface ISimpleSingleton {

        String Info { get; }

        ISimple Instance { get; }
        
    }

    [Guid("23f24607-0c2c-496e-ad03-98bd63b87d27")]
//    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ClassInterface(ClassInterfaceType.None)]
    public class SimpleSingleton : ServicedComponent, ISimpleSingleton {

        private static ISimple
            s_simple = (ISimple)new Simple();

        public ISimple Instance {
            get {
                Debug.WriteLine( "SimpleSingleton.Instance" );
                return s_simple;
            }
        }

        public String Info {
            get {
                Object[] os = 
                { 
                    Dns.GetHostName(), 
                    Simple.GetCurrentProcessId(),
                    Simple.GetCurrentThreadId(),
                    DateTime.Now
                };
                return String.Format( "machine = \"{0}\"\nprocess = {1}\nthread = {2}\ntime = \"{3}\"", os );

            }
        }
    }
    
}


эвенты через IConnectionPointContainer EventsCOM.CPP (ага, Managed C++, вот тут кол-во ссылок гляньте):
// compile
// cl -clr -LD -GX -MT -G6 -Ox EventsCOM.cpp
// потом суём в ГАК

#using <mscorlib.dll>
#using <System.dll>

[assembly: System::Reflection::AssemblyKeyFile("EventsCOM.snk")];

using namespace System::Runtime::InteropServices;

namespace {
    // чтобы много лишних имён не было открыто в сборке 
    #include <ocidl.h>
};

namespace EventsCOM {

public __gc class EventAdviser {
public:

    static int Advise( Object* sender, Object* receiver, System::Guid iid ) {
        IUnknown *recv=0, *send=0;
        IConnectionPointContainer *cpc=0;
        IConnectionPoint *cp=0;
        HRESULT hres;
        try {
            recv = (IUnknown*)(void*)Marshal::GetIUnknownForObject(receiver);

            unsigned char __pin* pbGuid = &iid.ToByteArray()[0];
            GUID* guid = (GUID*)pbGuid;

            send = (IUnknown*)(void*)Marshal::GetIUnknownForObject(sender);
        
            if (FAILED(hres=send->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc))) 
                Marshal::ThrowExceptionForHR(hres);
            if (FAILED(hres=cpc->FindConnectionPoint(*guid, &cp))) 
                Marshal::ThrowExceptionForHR(hres);
            DWORD cookie;
            if (FAILED(hres=cp->Advise(recv, &cookie))) 
                Marshal::ThrowExceptionForHR(hres);
            return cookie;
        } __finally {
            if (cp) cp->Release(); 
            if (cpc) cpc->Release();
            if (send) send->Release(); // ???????
            if (recv) cp->Release();   // ???????
        }
    }

    static void Unadvise( Object* sender, System::Guid iid, int cookie ) {
        IUnknown *send=0;
        IConnectionPointContainer *cpc=0;
        IConnectionPoint *cp=0;
        HRESULT hres;
        try {
            send = (IUnknown*)(void*)Marshal::GetIUnknownForObject(sender);

            unsigned char __pin* pbGuid = &iid.ToByteArray()[0];
            GUID* guid = (GUID*)pbGuid;
        
            if (FAILED(hres=send->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc))) 
                Marshal::ThrowExceptionForHR(hres);
            if (FAILED(hres=cpc->FindConnectionPoint(*guid, &cp))) 
                Marshal::ThrowExceptionForHR(hres);
            if (FAILED(hres=cp->Unadvise(cookie))) 
                Marshal::ThrowExceptionForHR(hres);
        } __finally {
            if (cp) cp->Release(); 
            if (cpc) cpc->Release();
            if (send) send->Release(); // ???????
        }
    }
};

};


и шарповский клиент ( линкуем с предыдущими двумя dll-ками ):
using System;
using System.Runtime.InteropServices;
using SimpleApp;
using EventsCOM;

class MyApp : ISimpleEvents 
{
    [MTAThread]
    static void Main (String[] args)
    {
        try {
            int res = CoInitializeSecurity( 0, -1, 0, 0, 1, 2, 0, 0, 0 );
            if (res<0) throw new COMException( "CoInitializeSecurity", res );

            ISimpleSingleton ss = new SimpleSingleton();
            Console.WriteLine( "\nISimpleSingleton.Info:\n" + ss.Info );

            ISimple s = ss.Instance;
            Console.WriteLine( "\nISimple.Info:\n" + s.Info );

            Console.WriteLine( "press <ENTER>..." );
            Console.ReadLine();

            MyApp ma = new MyApp();

            Console.WriteLine("GUID: " + typeof(ISimpleEvents).GUID);
            int cookie = EventAdviser.Advise(s, ma, typeof(ISimpleEvents).GUID);

            s.Fire( 2 );
            Console.WriteLine( "first fired( 2 )" );

            int cookie2 = EventAdviser.Advise(s, ma, typeof(ISimpleEvents).GUID);

            s.Fire( 1 );
            Console.WriteLine( "second fired( 1 )" );

            Console.WriteLine( "press <ENTER>..." );
            Console.ReadLine();

            EventAdviser.Unadvise(s, typeof(ISimpleEvents).GUID, cookie2);
            EventAdviser.Unadvise(s, typeof(ISimpleEvents).GUID, cookie);

        } catch( Exception e ) {
            Console.WriteLine( "EXCEPTION: " + e );
        }
    }

    public void OnInfoCB( string info ) {
        Console.WriteLine( "\nEVENT:\n" + info );
    }

    [DllImport("Ole32.dll"), PreserveSig]
    private static extern int CoInitializeSecurity(
        int pVoid,
        int cAuthSvc,
        int asAuthSvc,
        int pReserved1,
        int dwAuthnLevel,
        int dwImpLevel,
        int pAuthList,
        int dwCapabities,
        int pReserved3
    );
}
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: SCS  
Дата: 10.11.02 05:58
Оценка:
Здравствуйте zelyony, Вы писали:

Z>эвенты в виде делегатов я тоже заставить работать не смог

так про это и был разговор. Делегаты содержат ссылку на источник, который нужно сначала серелизовать в RealProxy на клиенте, а затем восстановить в ServicedComponentProxy на сервере. Последнее, увы, невозможно — другой домен и нет сборки клиента (и нет remoting'a).

Z>а вот подписку к интерфейсам и отписку реализовал через IConnectionPointContainer

Z>работает как надо
Z>подскажите на счёт ссылок в файле EventsCOM(там стоят "//???????") — to be or not to be (я про Release)

Попробуй без доп.библиотеки прямо на C#

  private UCOMIConnectionPoint icp; 
  private int cookie = -1; 
  ...
  // инициализация (привязка)
  UCOMIConnectionPointContainer icpc = (UCOMIConnectionPointContainer)Simple;
  Guid g = typeof(ISimpleEvents).GUID;
  icpc.FindConnectionPoint(ref g, out icp);
  icp.Advise(this, out cookie);
  ...
  // dispose (отвязка)
  if (-1 != cookie) icp.Unadvise(cookie);
  cookie = -1;


this, как и у тебя, должен наследовать интерфейс ISimpleEvents
SCS
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: Аноним  
Дата: 10.11.02 06:09
Оценка:
Здравствуйте SCS, Вы писали:

SCS>
SCS>  private UCOMIConnectionPoint icp; 
SCS>  private int cookie = -1; 
SCS>  ...
SCS>  // инициализация (привязка)
SCS>  UCOMIConnectionPointContainer icpc = (UCOMIConnectionPointContainer)Simple;
SCS>  Guid g = typeof(ISimpleEvents).GUID;
SCS>  icpc.FindConnectionPoint(ref g, out icp);
SCS>  icp.Advise(this, out cookie);
SCS>  ...
SCS>  // dispose (отвязка)
SCS>  if (-1 != cookie) icp.Unadvise(cookie);
SCS>  cookie = -1;
SCS>


SCS>this, как и у тебя, должен наследовать интерфейс ISimpleEvents


выделенная строка(или подобная) у меня почему-то не срабатывала
поэтому написал доп.сборку на С++
в любом случае ясности с ней в программе больше будет
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: Аноним  
Дата: 27.12.03 01:30
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Всем привет.


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


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

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

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

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


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


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


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


А как быть с наследованием реализаций интерфейсов, когда они заданы явно?


    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [GuidAttribute("03EAF9F0-3978-4651-9B42-7906DA07512F")]
    public interface IBase
    {
        string SayHello(string name);
    }

    [EventTrackingEnabledAttribute(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("0C75E2E9-6893-4A88-9B94-D972FB34A652")]
    public class Base : ServicedComponent, IBase
    {
        [AutoComplete]
        public string SayHello(string name)
        {
            return "Hello, " + name + "!";
        }
    }

    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [GuidAttribute("DF4DA93D-E39E-4F3F-9A19-6BEA5CCAE469")]
    public interface IDerived : IBase
    {
        string SayWelcome(string name);
    }

    [EventTrackingEnabledAttribute(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("964E0900-97C6-4B9C-8085-906B06DE432A")]
    public class Derived : Base, IDerived
    {
        string IDerived.SayWelcome(string name)
        {
            return "Welcome, " + name + "!";
        }
    }


SayHello через Derived вызвать не получается!!!
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.12.03 23:16
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>SayHello через Derived вызвать не получается!!!

И так:
IDerived obj = new Derived();
obj.SayHello("xxx");

?
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: Roman B  
Дата: 29.12.03 12:24
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, <Аноним>, Вы писали:


А>>SayHello через Derived вызвать не получается!!!

VD>И так:
VD>
VD>IDerived obj = new Derived();
VD>obj.SayHello("xxx");
VD>

VD>?

Если так сделать в C#-ом клиенте — всё проходит,
но при вызове этого метода через Derived из VBScript
(из COM+ объекта)
выскакивает ошибка типа "метод не поддрерживается".

Получается, что нужно в производный класс добавлять
методы базового...
Наследование в C# и COM — далеко не одно и то же...
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: mihailik Украина  
Дата: 29.12.03 14:39
Оценка:
VD>Итак почему же столько проблем с COM+-ом если компоненты, и особенно клиента создавать средствами .NET Framework?

А не прояснишь ещё, как взаимоотносятся концепции наследования интерфейсов в COM и .NET?

interface IMyInterface2 : IMyInterface


Может вообще нужно избегать наследования интерфейсов в .NET-компонентах, которые будут использоваться в COM/COM+?
... << RSDN@Home 1.1.0 stable >>
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: RomanB  
Дата: 30.12.03 10:52
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Я и в КОМ этим не пользовался. Куда проще и гибче реализовать два интерфейса.


А если нужно наследовать реализацию?
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: grat  
Дата: 30.12.03 11:03
Оценка:
Здравствуйте, VladD2.

Это все хорошо, только есть вопрос. Есть COM+ сервер, к нему подключаются клиенты. Хочется к каждому клиенту на стороне сервера привязать какую-то инфу, доступную для всех объектов, созданных на сервере этим клиентом. Как это сделать? [ThreadStatic] и Thread.SetData не работают, т.к. вызовы методов происходят в разных потоках. ContextUtil.ContextId уникален только в пределах одного объекта. System.Runtime.Remoting.Messaging.CallContext.GetData почему-то не всегда срабатывает. Что же делать? Не таскать же эту инфу между клиентом и сервером при каждом создании нового объекта?
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.03 13:19
Оценка:
Здравствуйте, RomanB, Вы писали:

RB>А если нужно наследовать реализацию?


С этим в дотнете вообще плохо. Обычно можно обойтись делегацией.

Но если грамотно проектировать интерфейс, то потребность в подключении реализации возникает не так часто. Видимо по этому ребята из МС и не уделяют этому вопросу должного внимания.


После праздников я планирую заняться этим проектом: Запись добровольцев...
Автор: VladD2
Дата: 23.12.03
. Его средствами даже на первых порах можно будет легко подключать реализации. Да и вообще гибкость будет ого-го.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.03 13:19
Оценка:
Здравствуйте, grat, Вы писали:

G>Это все хорошо, только есть вопрос. Есть COM+ сервер, к нему подключаются клиенты. Хочется к каждому клиенту на стороне сервера привязать какую-то инфу, доступную для всех объектов, созданных на сервере этим клиентом. Как это сделать? [ThreadStatic] и Thread.SetData не работают, т.к. вызовы методов происходят в разных потоках. ContextUtil.ContextId уникален только в пределах одного объекта. System.Runtime.Remoting.Messaging.CallContext.GetData почему-то не всегда срабатывает. Что же делать? Не таскать же эту инфу между клиентом и сервером при каждом создании нового объекта?


Это можно сделать или с помозю разделяемых свойств КОМ+-а (Shared Property Manager). Или просто создав синглтон-объект средствами дотнета.

Единственное что стоит учесть — это то что объекты могут загружаться в разных процессах (завист от конфигурации приложения). При этом ни один из способов работать не будет. Выходм может быть синглтон-КОМ-объект. Создать таковой без гемароя можно только на С++.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: mihailik Украина  
Дата: 30.12.03 13:57
Оценка:
RB>>А если нужно наследовать реализацию?

VD>С этим в дотнете вообще плохо. Обычно можно обойтись делегацией.


Вроде-бы где-то в недрах System.Runtime.InteropServices был специальный атрибут, который позволял сделать агрегацию COM-объекта в дотнет-объект.

То есть, нужно унаследовать дотнетовский объект от COM-объекта. Потом нужно сделать какой-то особый метод и пометить его особым атрибутом. Потому, что просто наследоваться от COM-объекта запрещается.
... << RSDN@Home 1.1.0 stable >>
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: grat  
Дата: 30.12.03 14:01
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это можно сделать или с помозю разделяемых свойств КОМ+-а (Shared Property Manager). Или просто создав синглтон-объект средствами дотнета.


VD>Единственное что стоит учесть — это то что объекты могут загружаться в разных процессах (завист от конфигурации приложения). При этом ни один из способов работать не будет. Выходм может быть синглтон-КОМ-объект. Создать таковой без гемароя можно только на С++.


Все объекты выполняются в контексте одного процесса на DCOM сервере. Вот пример:

// server
[assembly: ApplicationActivation(ActivationOption.Server)]

namespase Test
{
public class Class1: ServicedComponent
{
   [ContextStatic] internal static string str;
   public Class1() {}
   public void Method(string s)
   {
      str = s;
   }
}

public class Class2: ServicedComponent
{
   public Class2() {}
   public string Method()
   {
      return Class1.str;
   }
}
}


// client JScript
var c1 = new ActiveXObject("Test.Class1");
var c2 = new ActiveXObject("Test.Class2");
c1.Method("test1");
WScript.Echo(c2.Method());


Что надо сделать, чтобы одновременно работающие клиенты имели свое, уникальное, значение str?
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: mikа Stock#
Дата: 30.12.03 14:06
Оценка:
Здравствуйте, grat, Вы писали:

G>Что надо сделать, чтобы одновременно работающие клиенты имели свое, уникальное, значение str?


Попробуй MustRunInClientContextAttribute
Re[5]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: grat  
Дата: 30.12.03 14:10
Оценка:
Здравствуйте, mikа, Вы писали:

M>Здравствуйте, grat, Вы писали:


G>>Что надо сделать, чтобы одновременно работающие клиенты имели свое, уникальное, значение str?


M>Попробуй MustRunInClientContextAttribute


А если они на разных машинах?
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.12.03 03:12
Оценка:
Здравствуйте, mihailik, Вы писали:

M>Вроде-бы где-то в недрах System.Runtime.InteropServices был специальный атрибут, который позволял сделать агрегацию COM-объекта в дотнет-объект.


Насколько я понимаю речь идет о подключении готовой реализации к обычному КОМ-объекту.

M>То есть, нужно унаследовать дотнетовский объект от COM-объекта. Потом нужно сделать какой-то особый метод и пометить его особым атрибутом. Потому, что просто наследоваться от COM-объекта запрещается.


Незнаю. Я такого атрибута не видел.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.12.03 03:12
Оценка:
Здравствуйте, grat, Вы писали:

G>Что надо сделать, чтобы одновременно работающие клиенты имели свое, уникальное, значение str?


Клиенты?

Ну, для этого нужно лезть (методами КОМ-а) в кол-контекст... выскребать от туда юзера или проверять роль... и на основании этих данных искать информацию в неком глобальном объекте (например хэш-таблице).

А вообще, тогда уж лучше делать все объекты не стэйтлес и хранить нужные данные в них.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.12.03 03:12
Оценка:
Здравствуйте, grat, Вы писали:

G>А если они на разных машинах?


Это не сработает даже если они в разных процессах. В общем, плохая идея.
... << RSDN@Home 1.1.2 beta 1 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: Аноним  
Дата: 08.07.08 09:17
Оценка:
ЛЮДИ! У кого нибудь получилось создать ActiveX сомпонент у которого бы генерировались события? У меня нет, все перерыл. Тема старая, может ее кто нибудь уже решил. (FrameWork 2.0)
Re: Как создавать COM+-компоненты на .NET-е (это ответ, а не
От: Аноним  
Дата: 08.07.08 14:58
Оценка:
Всем привет!
НАРОД, НЕ ОБОЙДИТЕ СТОРОНОЙ!!!!!!

я этот вопрос уже задавал, но никто не ответил, может щас ктото знает, как мне решить пролблему???
я написал на С# СОМ компонент и хочу добавить возможность возвращать HRESULT. но у меня никак не получаэтся, кроме 0 или 1 нисчего не возвращает. я пробывал генерить COMException, но результат тот же, возвращает или 0, или 1. и, например, с С++ кода в блоке try ловит эксепшн, но не может его определить, сам обект НУЛЛ. пробывал вот так

......

public void Method()
{
.....
COMException("some description", 1);
......
}
........


а в с++ коде

.....
try
{
ISomePointer->Method();
}
catch(_com_error &error)
{

}
....

error получается НУЛЛ

ЕСЛИ КТОТО ЗНАЕТ ДРУГОЙ СПОСОБ, ЧТОБ ВОЗВРАТИТЬ HRESULT, ПОДСКАЖИТЕ ПЛЗ!!!
СПС.
Re[2]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: Аноним  
Дата: 08.07.08 15:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Всем привет!

А>НАРОД, НЕ ОБОЙДИТЕ СТОРОНОЙ!!!!!!
А>
А>я этот вопрос уже задавал, но никто не ответил, может щас ктото знает, как мне решить пролблему???
А>я написал на С# СОМ компонент и хочу добавить возможность возвращать HRESULT. но у меня никак не получаэтся, кроме 0 или 1 нисчего не возвращает. я пробывал генерить COMException, но результат тот же, возвращает или 0, или 1. и, например, с С++ кода в блоке try ловит эксепшн, но не может его определить, сам обект НУЛЛ. пробывал вот так


Marshal.ThrowExceptionForHR Method ?
Re[3]: Как создавать COM+-компоненты на .NET-е (это ответ, а
От: Аноним  
Дата: 09.07.08 10:23
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>>Всем привет!

А>>НАРОД, НЕ ОБОЙДИТЕ СТОРОНОЙ!!!!!!
А>>
А>>я этот вопрос уже задавал, но никто не ответил, может щас ктото знает, как мне решить пролблему???
А>>я написал на С# СОМ компонент и хочу добавить возможность возвращать HRESULT. но у меня никак не получаэтся, кроме 0 или 1 нисчего не возвращает. я пробывал генерить COMException, но результат тот же, возвращает или 0, или 1. и, например, с С++ кода в блоке try ловит эксепшн, но не может его определить, сам обект НУЛЛ. пробывал вот так


А>Marshal.ThrowExceptionForHR Method ?


Чет это не работает....
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.