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[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[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 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.