Re[2]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 16:53
Оценка: 6 (1)
Здравствуйте, MaximE, Вы писали:


ME>Каждый твой клиент делает CoCreateInstance. Твой класс CCoDasKernelServer должен быть

синглтоном, иначе каждый клиент будет создавать новый экземпляр CCoDasKernelServer.

ME>И что за client_object_list у тебя, что там хранится?




Так оно и есть. Я для этого и заношу все экземпляры CCoDasKernelServer-а в глобальный список на сервере(client_object_list) и затем пробегаюсь по нему, дёргая события, подсоединённые к каждому объекту.

Ведь в таком случае, синглетона можно избежать... Или я не прав где-то в корне?

#define MAX_CLIENTS 100

class CExeModule : public CComModule
{
public:
    void* client_object_list[MAX_CLIENTS];
    int client_counter;
.......





ME>
ME>STDMETHOD(FireUpdateContent)()                // Client's calls
ME>{
ME>    CCoDasKernelServer* p_server = NULL;
ME>    for (int i = 0; i < _Module.client_counter ; i++)
ME>    {
ME>        if (_Module.client_object_list[i] != NULL)
ME>        {
ME>            p_server = (CCoDasKernelServer*)(_Module.client_object_list[i]);
ME>            return p_server->UpdateContent(); // очень вот это смущает
ME>        }
ME>    }
ME>    return S_FALSE;    
ME>}

ME>
Проблема связи EXE-сервера с клиентами через ConnectionPoint
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 15:17
Оценка:
Ситуация такова:

Необходимо реализовать возможность уведомления всех клиентов EXE-сервера об периодических изменениях, происодящих в структуре данных сервера.

Сервер содержит кокласс с потоковой моделью MultiThreadModel, реализующий ConnectionPoint и ConnectionPointContainer, интерфейс для зажигания событий.

Из клиента, вошедших в MTA удаётся подключиться к событию, зажечеь его и даже обработать — тут вроде бы проблем нет. Все экземпляры этого кокласса сохраняются в глобальный список(при вызове конструктора), и когда один из клиентов зажигает событие, сервер пробегает по списку и вызывает соответсвующие методы из Sink-интерфейсов.
Вот код, всё это проделывающий:




//  метод для уведомления клиентов об изменениях
//  Список экземпляров содержит класс CExeModule. 
//  _Module, соответсвенно, его экземпляр.

STDMETHOD(FireUpdateContent)()                // Client's calls
{
    CCoDasKernelServer* p_server = NULL;
    for (int i = 0; i < _Module.client_counter ; i++)
    {
        if (_Module.client_object_list[i] != NULL)
        {
            p_server = (CCoDasKernelServer*)(_Module.client_object_list[i]);
            return p_server->UpdateContent();
        }
    }
    return S_FALSE;    
}




...........


// вызов синк-методов текущего экземпляра кокласса

STDMETHODIMP CCoDasKernelServer::UpdateContent()
{
    IConnectionPointImpl<CCoDasKernelServer, &IID_IUpdateContentEvent, CComDynamicUnkArray>* p = this;
    Lock();
    HRESULT hr = S_OK;
    IUnknown** pp = p->m_vec.begin();
    while (pp < p->m_vec.end() && hr == S_OK)
    {
        if (*pp != NULL)
        {
            IUpdateContentEvent* pIUpdateContentEvent = (IUpdateContentEvent*)*pp;
            hr = pIUpdateContentEvent->UpdateContent();
            if (FAILED(hr))
            {
                do_log(1, "Error calling event callback: UpdateContent...");
            }
        }
        pp++;
    }
    Unlock();
    return hr;
}



Как я и описал, события отлавливаются, НО только на ПЕРВОМ запущенном экземпляре клиента. События, зажжёные остальными клиентами, всё равно приходят к первому из них, хотя в списке экземпляров на сервере все они есть.
Подключаюсь к событиям с помощью AtlAdvize().

Вот код клиента(он один для всех, соответственно):


#include "stdafx.h"
#include "DialogClientTest.h"
#include "DialogClientTestDlg.h"

#include "initguid.h"

#include "c:\Home\mephody\dev\projects\Revision\DasControl\DasKernel\DasKernel.h"

#define IID_DEFINED
#include "c:\Home\mephody\dev\projects\Revision\DasControl\DasKernel\DasKernel_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CDialogClientTestApp theApp;
CComModule _Module;

class CDriver : 
            public CComObjectRootEx<CComMultiThreadModel>,
            public IUpdateContentEvent

{
public:
    CDriver() {}
    
BEGIN_COM_MAP(CDriver)
    COM_INTERFACE_ENTRY(IUpdateContentEvent)
END_COM_MAP()
public:

    HRESULT STDMETHODCALLTYPE UpdateContent(void)
    {
//        MessageBox(NULL, "UpdateContent event!", "CDriver", MB_OK);
        ((CDialogClientTestDlg*)(theApp.m_pMainWnd))->DoLogEvent(CString("UpdateContent event occured..."));
        return S_OK;
    }
};

IRegistration* obj = NULL;
IEvents* events = NULL;
DWORD coockie = 0;
CComObject<CDriver> *driver;


// И релизация подсоединения:

BOOL CDialogClientTestDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here


    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    _Module.Init(NULL, theApp.m_hInstance);

    HRESULT hr = S_OK;
    
    hr = CoCreateInstance(CLSID_CoDasKernelServer, NULL, CLSCTX_ALL, IID_IRegistration, (void**)(&obj));

    CComObject<CDriver>::CreateInstance(&driver);
    
    if (SUCCEEDED(hr))
    {
        hr = obj->QueryInterface(IID_IEvents, (void**)(&events));
        if (SUCCEEDED(hr))
        {
            hr = AtlAdvise(events, driver->GetUnknown(), IID_IUpdateContentEvent, &coockie);
            if (SUCCEEDED(hr))
            {
                hr = events->FireUpdateContent();

                if (FAILED(hr))
                {
                    MessageBox("Failed FireUpdateContent...", "Error!", MB_OK);
                }

            }else 
                AfxMessageBox("Failed advise...");
        } else
            AfxMessageBox("Failed to QueryInterface DIID_IMyClassEvents...");
    } else
        AfxMessageBox("Failed to create obj...");

    return TRUE;  // return TRUE  unless you set the focus to a control
}



Возможно, проблема в том, что для всех экземпляров клиента используется один и тот же класс CDriver?
То есть, ему не задаётся уникальный CLSID. Тогда как ему назначить CLASSID так, чтобы события работали для всех запущеных экземпляров этого клиента? Ну или, хотябы, как вообще назначить CLSID в этом случае?

Заранее спасибо.
Прошу прощение за длинное письмо — никак не удаётся свести концы с концами, запутался...
Re: Проблема связи EXE-сервера с клиентами через ConnectionP
От: Аноним  
Дата: 27.11.02 15:31
Оценка:
Все это здорово, но если наши объекты находтся в MTA, то мы сами отвечаем за их синхронизацию,
это касается не только сервера, но и клиента.
Проверить это достаточно просто, либо:
— перевести клиента в STA
— добавить синхронизацию в реализацию CDriver::UpdateContent
как идея


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

M>Ситуация такова:


M>Необходимо реализовать возможность уведомления всех клиентов EXE-сервера об периодических изменениях, происодящих в структуре данных сервера.


M>Сервер содержит кокласс с потоковой моделью MultiThreadModel, реализующий ConnectionPoint и ConnectionPointContainer, интерфейс для зажигания событий.


M>Из клиента, вошедших в MTA удаётся подключиться к событию, зажечеь его и даже обработать — тут вроде бы проблем нет. Все экземпляры этого кокласса сохраняются в глобальный список(при вызове конструктора), и когда один из клиентов зажигает событие, сервер пробегает по списку и вызывает соответсвующие методы из Sink-интерфейсов.

M>Вот код, всё это проделывающий:

M>


M>

M>
M>//  метод для уведомления клиентов об изменениях
M>//  Список экземпляров содержит класс CExeModule. 
M>//  _Module, соответсвенно, его экземпляр.

M>STDMETHOD(FireUpdateContent)()                // Client's calls
M>{
M>    CCoDasKernelServer* p_server = NULL;
M>    for (int i = 0; i < _Module.client_counter ; i++)
M>    {
M>        if (_Module.client_object_list[i] != NULL)
M>        {
M>            p_server = (CCoDasKernelServer*)(_Module.client_object_list[i]);
M>            return p_server->UpdateContent();
M>        }
M>    }
M>    return S_FALSE;    
M>}
M>


M>


M>...........


M>

M>
M>// вызов синк-методов текущего экземпляра кокласса

M>STDMETHODIMP CCoDasKernelServer::UpdateContent()
M>{
M>    IConnectionPointImpl<CCoDasKernelServer, &IID_IUpdateContentEvent, CComDynamicUnkArray>* p = this;
M>    Lock();
M>    HRESULT hr = S_OK;
M>    IUnknown** pp = p->m_vec.begin();
M>    while (pp < p->m_vec.end() && hr == S_OK)
M>    {
M>        if (*pp != NULL)
M>        {
M>            IUpdateContentEvent* pIUpdateContentEvent = (IUpdateContentEvent*)*pp;
M>            hr = pIUpdateContentEvent->UpdateContent();
M>            if (FAILED(hr))
M>            {
M>                do_log(1, "Error calling event callback: UpdateContent...");
M>            }
M>        }
M>        pp++;
M>    }
M>    Unlock();
M>    return hr;
M>}
M>


M>

M>Как я и описал, события отлавливаются, НО только на ПЕРВОМ запущенном экземпляре клиента. События, зажжёные остальными клиентами, всё равно приходят к первому из них, хотя в списке экземпляров на сервере все они есть.
M>Подключаюсь к событиям с помощью AtlAdvize().

M>Вот код клиента(он один для всех, соответственно):


M>

M>
M>#include "stdafx.h"
M>#include "DialogClientTest.h"
M>#include "DialogClientTestDlg.h"

M>#include "initguid.h"

M>#include "c:\Home\mephody\dev\projects\Revision\DasControl\DasKernel\DasKernel.h"

M>#define IID_DEFINED
M>#include "c:\Home\mephody\dev\projects\Revision\DasControl\DasKernel\DasKernel_i.c"

M>#ifdef _DEBUG
M>#define new DEBUG_NEW
M>#undef THIS_FILE
M>static char THIS_FILE[] = __FILE__;
M>#endif

M>extern CDialogClientTestApp theApp;
M>CComModule _Module;

M>class CDriver : 
M>            public CComObjectRootEx<CComMultiThreadModel>,
M>            public IUpdateContentEvent

M>{
M>public:
M>    CDriver() {}
M>    
M>BEGIN_COM_MAP(CDriver)
M>    COM_INTERFACE_ENTRY(IUpdateContentEvent)
M>END_COM_MAP()
M>public:

M>    HRESULT STDMETHODCALLTYPE UpdateContent(void)
M>    {
M>//        MessageBox(NULL, "UpdateContent event!", "CDriver", MB_OK);
M>        ((CDialogClientTestDlg*)(theApp.m_pMainWnd))->DoLogEvent(CString("UpdateContent event occured..."));
M>        return S_OK;
M>    }
M>};

M>IRegistration* obj = NULL;
M>IEvents* events = NULL;
M>DWORD coockie = 0;
M>CComObject<CDriver> *driver;

M>
M>// И релизация подсоединения:

M>BOOL CDialogClientTestDlg::OnInitDialog()
M>{
M>    CDialog::OnInitDialog();

M>    SetIcon(m_hIcon, TRUE);            // Set big icon
M>    SetIcon(m_hIcon, FALSE);        // Set small icon
M>    
M>    // TODO: Add extra initialization here

M>
M>    CoInitializeEx(NULL, COINIT_MULTITHREADED);

M>    _Module.Init(NULL, theApp.m_hInstance);

M>    HRESULT hr = S_OK;
M>    
M>    hr = CoCreateInstance(CLSID_CoDasKernelServer, NULL, CLSCTX_ALL, IID_IRegistration, (void**)(&obj));

M>    CComObject<CDriver>::CreateInstance(&driver);
M>    
M>    if (SUCCEEDED(hr))
M>    {
M>        hr = obj->QueryInterface(IID_IEvents, (void**)(&events));
M>        if (SUCCEEDED(hr))
M>        {
M>            hr = AtlAdvise(events, driver->GetUnknown(), IID_IUpdateContentEvent, &coockie);
M>            if (SUCCEEDED(hr))
M>            {
M>                hr = events->FireUpdateContent();

M>                if (FAILED(hr))
M>                {
M>                    MessageBox("Failed FireUpdateContent...", "Error!", MB_OK);
M>                }

M>            }else 
M>                AfxMessageBox("Failed advise...");
M>        } else
M>            AfxMessageBox("Failed to QueryInterface DIID_IMyClassEvents...");
M>    } else
M>        AfxMessageBox("Failed to create obj...");

M>    return TRUE;  // return TRUE  unless you set the focus to a control
M>}

M>


M>

M>Возможно, проблема в том, что для всех экземпляров клиента используется один и тот же класс CDriver?
M>То есть, ему не задаётся уникальный CLSID. Тогда как ему назначить CLASSID так, чтобы события работали для всех запущеных экземпляров этого клиента? Ну или, хотябы, как вообще назначить CLSID в этом случае?

M>Заранее спасибо.

M>Прошу прощение за длинное письмо — никак не удаётся свести концы с концами, запутался...
Re[2]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 15:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Все это здорово, но если наши объекты находтся в MTA, то мы сами отвечаем за их синхронизацию,

А>это касается не только сервера, но и клиента.
А>Проверить это достаточно просто, либо:
А>- перевести клиента в STA
А>- добавить синхронизацию в реализацию CDriver::UpdateContent
А>как идея

То есть, вы хотите сказать, что тут проблема в синхронизации? Я сделал клиента STA — ничего не изменилось.
Можно по подробнее, что вы имели в виду? Ведь, вроде бы, (не)синхронизация тут пока большой(негативной) роли играть не может...
Re: Проблема связи EXE-сервера с клиентами через ConnectionP
От: MaximE Великобритания  
Дата: 27.11.02 16:41
Оценка:
Здравствуйте, mephody, Вы писали:

M>Ситуация такова:


M>Необходимо реализовать возможность уведомления всех клиентов EXE-сервера об периодических изменениях, происодящих в структуре данных сервера.


M>Сервер содержит кокласс с потоковой моделью MultiThreadModel, реализующий ConnectionPoint и ConnectionPointContainer, интерфейс для зажигания событий.


M>Из клиента, вошедших в MTA удаётся подключиться к событию, зажечеь его и даже обработать — тут вроде бы проблем нет. Все экземпляры этого кокласса сохраняются в глобальный список(при вызове конструктора), и когда один из клиентов зажигает событие, сервер пробегает по списку и вызывает соответсвующие методы из Sink-интерфейсов.

M>Вот код, всё это проделывающий:

Каждый твой клиент делает CoCreateInstance. Твой класс CCoDasKernelServer должен быть синглтоном, иначе каждый клиент будет создавать новый экземпляр CCoDasKernelServer.

И что за client_object_list у тебя, что там хранится?

STDMETHOD(FireUpdateContent)()                // Client's calls
{
    CCoDasKernelServer* p_server = NULL;
    for (int i = 0; i < _Module.client_counter ; i++)
    {
        if (_Module.client_object_list[i] != NULL)
        {
            p_server = (CCoDasKernelServer*)(_Module.client_object_list[i]);
            return p_server->UpdateContent(); // очень вот это смущает
        }
    }
    return S_FALSE;    
}
Re[2]: Проблема связи EXE-сервера с клиентами через Connecti
От: Ivan Россия www.rsdn.ru
Дата: 27.11.02 16:55
Оценка:
Здравствуйте, MaximE, Вы писали:

ME> return p_server->UpdateContent(); // очень вот это смущает

Проблема по-моему именно в инструкции return — надо ведь весь список просматировать, а не только первый элемент.
А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.
Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON
Re[3]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:18
Оценка:
Здравствуйте, Ivan, Вы писали:

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


ME>> return p_server->UpdateContent(); // очень вот это смущает

I>Проблема по-моему именно в инструкции return — надо ведь весь список просматировать, а не только первый элемент.
I>А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.
I>Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON

Да, но p_server — это и есть i-й элемент списка всех экземпляров. Вот тут мы по нему довольно корректно пробегаемся. Причём, проверено, что список состоит не из одного элемента, и все они разные (что и должно быть). Непонятно, почему вызывается всё время callback самого первого объекта. Возможно, опять же, — дело в отсутсвующем CLSID для клиентского класса, реализующего sink интерфейс... Как это исправить, не применяя всё-таки синглетон?

Спасибо.
Re[3]: Проблема связи EXE-сервера с клиентами через Connecti
От: MaximE Великобритания  
Дата: 27.11.02 17:20
Оценка:
Здравствуйте, Ivan, Вы писали:

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


ME>> return p_server->UpdateContent(); // очень вот это смущает

I>Проблема по-моему именно в инструкции return — надо ведь весь список просматировать, а не только первый элемент.
I>А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.
I>Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON

Вообще-то, COM-синглтон в заднице. Для inproc это еще как-то применимо.
Но что значит COM-синглтон в распределенной системе? Никакого load-balancing'а и еще куча геморроя.
Лучше использовать объекты с shared state. Самая простая и наивная реализация объекта может применять static члены для разделения состояния (но опять же, это применимо только локально + сервер singleuse).
Так же, IConnectionPointContainer крайне громоздок и неоптимален (проектировщик этого интерфеса не слышал про [iid_is]) и применим только для inproc. В остальных случаях рекомендуется реализовывать свой механизм соединений.
Re[4]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:20
Оценка:
Здравствуйте, mephody, Вы писали:

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


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


ME>>> return p_server->UpdateContent(); // очень вот это смущает

I>>Проблема по-моему именно в инструкции return — надо ведь весь список просматировать, а не только первый элемент.
I>>А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.
I>>Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON



M>Да, но p_server — это и есть i-й элемент списка всех экземпляров. Вот тут мы по нему довольно корректно пробегаемся.


Сорри, вот метод, вызываемый одним из клиентов для уведомления всех остальных клиентов:


STDMETHOD(FireUpdateContent)()                // Client's calls
{
    CCoDasKernelServer* p_server = NULL;
    for (int i = 0; i < _Module.client_counter ; i++)
    {
        if (_Module.client_object_list[i] != NULL)
        {
            p_server = (CCoDasKernelServer*)(_Module.client_object_list[i]);
            return p_server->UpdateContent(); // что же всё-таки тут не так?
        }
    }
    return S_FALSE;    
}



Причём, проверено, что список состоит не из одного элемента, и все они разные (что и должно быть). Непонятно, почему вызывается всё время callback самого первого объекта. Возможно, опять же, — дело в отсутсвующем CLSID для клиентского класса, реализующего sink интерфейс... Как это исправить, не применяя всё-таки синглетон?

M>Спасибо.
Re[3]: Проблема связи EXE-сервера с клиентами через Connecti
От: MaximE Великобритания  
Дата: 27.11.02 17:22
Оценка:
Здравствуйте, mephody, Вы писали:



ME>>И что за client_object_list у тебя, что там хранится?


M>


M>Так оно и есть. Я для этого и заношу все экземпляры CCoDasKernelServer-а в глобальный список на сервере(client_object_list) и затем пробегаюсь по нему, дёргая события, подсоединённые к каждому объекту.


M>Ведь в таком случае, синглетона можно избежать... Или я не прав где-то в корне?


Абсолютно прав и именно в корне. В COM'е синглтона надо избегать.
Re[4]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:25
Оценка:
Здравствуйте, MaximE, Вы писали:


M>>Так оно и есть. Я для этого и заношу все экземпляры CCoDasKernelServer-а в глобальный список на сервере(client_object_list) и затем пробегаюсь по нему, дёргая события, подсоединённые к каждому объекту.


M>>Ведь в таком случае, синглетона можно избежать... Или я не прав где-то в корне?


ME>Абсолютно прав и именно в корне. В COM'е синглтона надо избегать.



Это я в курсе... Вопрос в том, — КАК?
Re[4]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:29
Оценка:
Здравствуйте, MaximE, Вы писали:

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


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


ME>>> return p_server->UpdateContent(); // очень вот это смущает

I>>Проблема по-моему именно в инструкции return — надо ведь весь список просматировать, а не только первый элемент.
I>>А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.
I>>Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON

ME>Вообще-то, COM-синглтон в заднице. Для inproc это еще как-то применимо.

ME>Но что значит COM-синглтон в распределенной системе? Никакого load-balancing'а и еще куча геморроя.
ME>Лучше использовать объекты с shared state. Самая простая и наивная реализация объекта может применять static члены для разделения состояния (но опять же, это применимо только локально + сервер singleuse).
ME>Так же, IConnectionPointContainer крайне громоздок и неоптимален (проектировщик этого интерфеса не слышал про [iid_is]) и применим только для inproc. В остальных случаях рекомендуется реализовывать свой механизм соединений.


Ок, значит, проблема в использовании IConnectionPointContainer? Где можно точно удостовериться(дайте ссылку или книжку, плз), что он не применим в случае распределённых систем (EXE-серверы)? Не хотелось бы всё перелопачивать, и напрягать людей, пишуших клиентов. Ведь вроде бы всё там логично... Все потоки, какие там есть входят в МТА. С маршалингом проблем быть не должно.
Re[5]: Проблема связи EXE-сервера с клиентами через Connecti
От: Slamin США  
Дата: 27.11.02 17:31
Оценка:
Здравствуйте, mephody, Вы писали:

M> return p_server->UpdateContent(); // что же всё-таки тут не так?


M>

M>Причём, проверено, что список состоит не из одного элемента, и все они разные (что и должно быть). Непонятно, почему вызывается всё время callback самого первого объекта. Возможно, опять же, — дело в отсутсвующем CLSID для клиентского класса, реализующего sink интерфейс... Как это исправить, не применяя всё-таки синглетон?

M>>Спасибо.


return тут не к чему, поэтому и вызывается только первый в списке. Цикл то обрывается на первом же не нулевом CCoDasKernelServer*.
There are 10 types of people in the world, those who don't understand binaries, those who do, and those who understand not only binaries.
Re[6]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:41
Оценка:
Здравствуйте, Slamin, Вы писали:

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


M>> return p_server->UpdateContent(); // что же всё-таки тут не так?


M>>

M>>Причём, проверено, что список состоит не из одного элемента, и все они разные (что и должно быть). Непонятно, почему вызывается всё время callback самого первого объекта. Возможно, опять же, — дело в отсутсвующем CLSID для клиентского класса, реализующего sink интерфейс... Как это исправить, не применяя всё-таки синглетон?

M>>>Спасибо.


S>return тут не к чему, поэтому и вызывается только первый в списке. Цикл то обрывается на первом же не нулевом CCoDasKernelServer*.


Ха!!! Чёрт, я с детства кривоват...

Ура! Спасибо всем. Всё сразу заработало.
Re[5]: Проблема связи EXE-сервера с клиентами через Connecti
От: MaximE Великобритания  
Дата: 27.11.02 17:45
Оценка:
Здравствуйте, mephody, Вы писали:

M>Ок, значит, проблема в использовании IConnectionPointContainer? Где можно точно удостовериться(дайте ссылку или книжку, плз), что он не применим в случае распределённых систем (EXE-серверы)? Не хотелось бы всё перелопачивать, и напрягать людей, пишуших клиентов. Ведь вроде бы всё там логично... Все потоки, какие там есть входят в МТА. С маршалингом проблем быть не должно.


Effective COM Programming: Seven Tips for Building Better COM-based Applications
Re[6]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 17:47
Оценка:
Здравствуйте, MaximE, Вы писали:

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


M>>Ок, значит, проблема в использовании IConnectionPointContainer? Где можно точно удостовериться(дайте ссылку или книжку, плз), что он не применим в случае распределённых систем (EXE-серверы)? Не хотелось бы всё перелопачивать, и напрягать людей, пишуших клиентов. Ведь вроде бы всё там логично... Все потоки, какие там есть входят в МТА. С маршалингом проблем быть не должно.


ME>Effective COM Programming: Seven Tips for Building Better COM-based Applications



Большое спасибо. Проблема решилась. Дело было просто в невнимательности. return — там был совсем ни к чему. Теперь всё работает даже с ConnPointCont.
Re[4]: Проблема связи EXE-сервера с клиентами через Connecti
От: Ivan Россия www.rsdn.ru
Дата: 27.11.02 17:47
Оценка:
Здравствуйте, MaximE, Вы писали:

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


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


I>>А вообще гораздо лучше использовать синглтон и не заморачиваться со всякими списками в _Module.

I>>Правда стандартный синглтон в ATL немного кривоват — объект разрушается только при выгрузке модуля и не очень хорошо живется STA-шным синглтонам, а в целом пользоваться можно, см. DECLARE_CLASSFACTORY_SINGLETON

ME>Вообще-то, COM-синглтон в заднице.


Обеими руками за, но ...
Главная проблема синглтона в плохой масштабируемости — когда количество клиентов велико. Если речь идет о 1-5 клиентах, то он очень даже применим, другой вопрос в том, что нормальную реализацию трудно найти(написать).
Re[4]: Проблема связи EXE-сервера с клиентами через Connecti
От: Ivan Россия www.rsdn.ru
Дата: 27.11.02 17:54
Оценка:
Здравствуйте, mephody, Вы писали:

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


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


M>Да, но p_server — это и есть i-й элемент списка всех экземпляров.

Тогда я ничего не понимаю

Каждый клиент создает свой экземпляр серверного компонента. Все они добавляются в список. Каждый клиент Advise'ится к свою экземпляру сервера. Чтобы событие получили все клиенты надо сделать следующее:
пройти по всем серверам, у каждого пройти по всем подключенным клиентам. А у тебя в коде написано
return p_server->UpdateContent();

то есть после первого сервера все кончится, а это как раз и приведет к тому, что событие будет получено только первым клиентом.
Re[5]: Проблема связи EXE-сервера с клиентами через Connecti
От: mephody Великобритания http://www.linkedin.com/pub/2/79/aa2
Дата: 27.11.02 18:03
Оценка:
Здравствуйте, Ivan, Вы писали:

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


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


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


M>>Да, но p_server — это и есть i-й элемент списка всех экземпляров.

I>Тогда я ничего не понимаю

I>Каждый клиент создает свой экземпляр серверного компонента. Все они добавляются в список. Каждый клиент Advise'ится к свою экземпляру сервера. Чтобы событие получили все клиенты надо сделать следующее:

I>пройти по всем серверам, у каждого пройти по всем подключенным клиентам. А у тебя в коде написано
I>
I>return p_server->UpdateContent();
I>

I>то есть после первого сервера все кончится, а это как раз и приведет к тому, что событие будет получено только первым клиентом.


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