Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание СОМ-сервера  (Прочитано 22197 раз)
0 Пользователей и 1 Гость смотрят эту тему.
SSW
Гость
« : 01-12-2004 14:37 » 

Windows / VC++ 6.0 / MFC

Надо создать две программы: сервер и клиент.
Клиент отправляет параметры функции которая на сервере, и та выполняет свою работу. Результат возвращает клиенту.

Сервер начал делать как обычный проект на основе диалога, добавив при создании галочку Automation. Что доло возможность легко работать с интерфейсами. Потом создание функции, функцию в поток, общение с клиентом... и т.д. и т.п.

Клиент - обычный проект на диалоге. В котором добавлен клас, как работать с итерфейсом.

И вот, проблема.
При запуске клиента запускается сервер.

Код:
class {MyMFCServer : public COleDispatchDriver

Код:
IMyMFCServer ci;

Код:
BOOL CMyMFCClientDlg::OnInitDialog()
{
     CDialog::OnInitDialog();
     AfxOleInit();
     if (!ci.CreateDispatch("MyMFCServer.Application")) |AfxMessageBox("Not connect whis server");" else AfxMessageBox("Server Connected !!!");
...
  // Add "About..." menu item to system menu.
...
Это в принцыпе нормально. Но есть небольшое НО.
Если клиентов много, то программа-сервер запускается для каждого клиента своя.  Так больше нельзя...

Вопрос :
Как с этим бороться?

Надо чтобы программа-сервер была одна для всех клиентов.
Непосредственно запуск сервера делает
ci.CreateDispatch("MyMFCServer.Application")

Может есть какойто метод проверки, запущен ли этот сервер. Если нет, то уже тогда запускать?

Или может есть другой выход?
« Последнее редактирование: 02-12-2007 18:51 от Алексей1153++ » Записан
baldr
Команда клуба

cy
Offline Offline
Пол: Мужской
Дорогие россияне


WWW
« Ответ #1 : 01-12-2004 15:43 » 

Насколько я знаю, это делается с помощью мьютексов...
Цитата: MSDN
An object of class CMutex represents a “mutex” — a synchronization object that allows one thread mutually exclusive access to a resource. Mutexes are useful when only one thread at a time can be allowed to modify data or some other controlled resource. For example, adding nodes to a linked list is a process that should only be allowed by one thread at a time. By using a CMutex object to control the linked list, only one thread at a time can gain access to the list.

Вот - в MFC есть класс CMutex.
Записан

Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
SSW
Гость
« Ответ #2 : 01-12-2004 15:54 » 

На скоко я понимаю (хотя опыта мало, могу ошибаться) CMutex используется для синхронизации потоков. Тоесть если есть много потоков, а обьект над которым они ратотают один. Тогда с помощью CMutex можно задать какому потоку в какой ситуации че надо делать.
Записан
GlukSoft
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 02-12-2004 06:29 » 

SSW, можно создать именованный mutex в сервере и перед запуском сервера проверять его наличие, если он уже существует, то сервер повторно запускать не надо.
Записан

Fatal error C1: Brain expected
SSW
Гость
« Ответ #4 : 02-12-2004 07:52 » 

А как в таком случаи приконектить Dispatch?
При запуске клиента, он создается вместе с запуском сервера.
Код:
class IMyMFCServer : public COleDispatchDriver
...
IMyMFCServer ci;
...
ci.CreateDispatch("MyMFCServer.Application")
Если делать так как вы советуете, то надо каким-то другим макаром содавать этот Dispatch.
« Последнее редактирование: 02-12-2007 18:52 от Алексей1153++ » Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #5 : 02-12-2004 08:53 » 

SSW, не надо никаких мутехов, щас пару сек посмотрю как это делается
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
Pu
Большой босс

ru
Offline Offline
78


« Ответ #6 : 02-12-2004 09:15 » 

короче . надо просто регистрировать класс сервера с флагами REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED. и усе. сервер должен будет запуститься один раз и все последующие вызовы будут на него же. вроде все.
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
SSW
Гость
« Ответ #7 : 02-12-2004 09:45 » 

Чето я немогу найти где их зарегистрировать. :oops:
Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #8 : 02-12-2004 09:48 » 

SSW, во первых , у тебя какой сервер? длл или ехе?
в ехе сервере надо смотреть функцию CoRegisterClassObject. В ней как бы и есть эти флаги.
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
SSW
Гость
« Ответ #9 : 02-12-2004 10:04 » 

Сервер у меня ехе. Но вот функции CoRegisterClassObject - НЕТ!  Так больше нельзя...

Поиск по проекту на слово "reg" дал 4 результата
Цитата

Searching for 'reg'...
C:\project\MyMFCServer\MyMFCServer.cpp(67):      // Register all OLE server (factories) as running.  This enables the
C:\project\MyMFCServer\MyMFCServer.cpp(69):      COleTemplateServer::RegisterAll();
C:\project\MyMFCServer\MyMFCServer.cpp(74):      //  to update the system registry in case it has been damaged.
C:\project\MyMFCServer\MyMFCServer.cpp(75):      COleObjectFactory::UpdateRegistryAll();
4 occurrence(s) have been found.


И флагов нигде нет Жаль
Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #10 : 02-12-2004 10:30 » 

SSW, смотри функцию аналог main в ней должен быть вызов функции регистрирующей класс.  А  CoRegisterClassObject спрятана в мфс
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
SSW
Гость
« Ответ #11 : 02-12-2004 12:21 » 

Ты имеешь в виду

BOOL CMyMFCServerApp::InitInstance()
Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #12 : 02-12-2004 12:40 » 

не , имею ввиду то что в АТЛ выглядит как
Код:
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, 
    HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)

там есть регистрация в реестре и запуск сервера в зависимости от параметров
дык регистрация класса в АТЛ осуществляется строкой
Код:
        hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, 
            REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
в мфс должно быть нечто похожее, я с мфс не работаю так что точно не знаю как оно там выглядит.
« Последнее редактирование: 02-12-2007 18:53 от Алексей1153++ » Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
Oleg I
Гость
« Ответ #13 : 02-12-2004 14:54 » 

Года 2 -3 тому назад у меня возникла похожая проблемма. Я делал так:

В StdAfx.h

Цитата

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__4DFD8FE1_A3D5_11D3_8E20_0060520595FD__INCLUDED_)
#define AFX_STDAFX_H__4DFD8FE1_A3D5_11D3_8E20_0060520595FD__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define OEMRESOURCE

#define VC_EXTRALEAN      // Exclude rarely-used stuff from Windows headers

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdisp.h>        // MFC Automation classes
#include <afxdtctl.h>      // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>         // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT

#include <afxmt.h>

// This macro is the same as IMPLEMENT_OLECREATE, except it passes TRUE
//  for the bMultiInstance parameter to the COleObjectFactory constructor.
//  We want a separate instance of this application to be launched for
//  each automation proxy object requested by automation controllers.
#ifndef IMPLEMENT_OLECREATE2
#define IMPLEMENT_OLECREATE2(class_name, external_name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
   AFX_DATADEF COleObjectFactory class_name::factory(class_name::guid, \
      RUNTIME_CLASS(class_name), TRUE, _T(external_name)); \
   const AFX_DATADEF GUID class_name::guid = \
      { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } };
#endif // IMPLEMENT_OLECREATE2

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__4DFD8FE1_A3D5_11D3_8E20_0060520595FD__INCLUDED_)


TRUE в COleObjectFactory как раз и дает запускаться серверу 1 раз.

InitInstance() выглядел примерно так:

Цитата

BOOL MyProdjectApp::InitInstance()
{
   // Initialize OLE libraries
  if (!AfxOleInit())
  {
    AfxMessageBox(IDP_OLE_INIT_FAILED);
    return FALSE;
  }

  AfxEnableControlContainer();

  // Standard initialization
  // If you are not using these features and wish to reduce the size
  //  of your final executable, you should remove from the following
  //  the specific initialization routines you do not need.

#ifdef _AFXDLL
  Enable3dControls();         // Call this when using MFC in a shared DLL
#else
  Enable3dControlsStatic();   // Call this when linking to MFC statically
#endif

...{ My Code }      ...

  // Parse the command line to see if launched as OLE server
  if (RunEmbedded() || RunAutomated())
  {
    // Register all OLE server (factories) as running.  This enables the
    //  OLE libraries to create objects from other applications.
    COleTemplateServer::RegisterAll();
  }
  else
  {
    // When a server application is launched stand-alone, it is a good idea
    //  to update the system registry in case it has been damaged.
    COleObjectFactory::UpdateRegistryAll();

    if(AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
    {
      //AfxMessageBox("Сервер My успешно зарегистрирован!");
    }
    else
    {
      AfxMessageBox("Невозможно зарегистрировать библиотеку типов для сервера My!", MB_TOPMOST);
    }


...{ My Code }      ...

    #ifdef _DRIVER
      return FALSE;
    #endif
  }


...{ My Code }      ...


  #ifdef _DRIVER
      return TRUE;
  #endif

//////////////////////////////////////////////////////////////////////////////
//   int nResponse = dlg->DoModal();
//   if (nResponse == IDOK)
//   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with OK
//   }
//   else if (nResponse == IDCANCEL)
//   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with Cancel
//   }
   
  // Since the dialog has been closed, return FALSE so that we exit the
   //  application, rather than start the application's message pump.
   return FALSE;
}


Все это я прочитал в книге Дж.Мюллер "Visual C++ 5"
Записан
SSW
Гость
« Ответ #14 : 02-12-2004 15:38 » 

Нет! все равно не работает!

Мне кажется проблема в этом гребаном Dispatch :new_shot:  :new_shot:  :new_shot:

А как в таком случаи приконектить Dispatch?
При запуске клиента, он создается вместе с запуском сервера.

Код:
class {MyMFCServer : public COleDispatchDriver 
...
IMyMFCServer ci;
...
ci.CreateDispatch("MyMFCServer.Application")

Если делать так как вы советуете, то надо каким-то другим макаром содавать этот Dispatch.
« Последнее редактирование: 02-12-2007 18:54 от Алексей1153++ » Записан
Oleg I
Гость
« Ответ #15 : 02-12-2004 16:24 » 

В клиенте у меня было:
Цитата

/////////////////////////////////////////////////////////////////////////////
// CMyTestApp initialization

BOOL CMyTestApp::InitInstance()
{
   // Initialize OLE libraries
   if (!AfxOleInit())
   {
      AfxMessageBox(IDP_OLE_INIT_FAILED);
      return FALSE;
   }

   AfxEnableControlContainer();

   // Standard initialization
   // If you are not using these features and wish to reduce the size
   //  of your final executable, you should remove from the following
   //  the specific initialization routines you do not need.

#ifdef _AFXDLL
   Enable3dControls();         // Call this when using MFC in a shared DLL
#else
   Enable3dControlsStatic();   // Call this when linking to MFC statically
#endif

  lClientReg = 0;

  hInstance = AfxGetResourceHandle();
  if (!MyDrv.CreateDispatch(szMyControlObject))
  {
    DWORD dwErr=GetLastError();
    return FALSE;
  }
  MyDrv.ShowMessages(TRUE);
  HRESULT hRes = MyDrv.QueryIds();
  if (hRes != S_OK)
  {
    AfxMessageBox("Найдены не все функции");
  }

  pMyEvents = new MyEventHandler(this);
  pMyEvents->Register((LPOLEOBJECT)(LPDISPATCH)MyDrv, &dwClientId);
  CLIENT_PARAM Param;
  Param.dwId = dwClientId;
  Param.dwSetNotifyFlag = CPCLI_NOTIFY_PORTINFO | CPCLI_NOTIFY_CLIENTINFO;
  theApp.lClientReg ++;
  long lRet;
//  dlgSet = &((MyDrvApp *) GetParent())->dlgSet;
  lRet = theApp.MyDrv.SetClientParam(&Param);

   m_csSaveFileName = _T("ProtSZS.txt");
  m_bProtokol = FALSE;

   CMyTestDlg dlg;

   m_pMainWnd = &dlg;
   int nResponse = dlg.DoModal();
   if (nResponse == IDOK)
   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with OK
   }
   else if (nResponse == IDCANCEL)
   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with Cancel
   }
//  MyDrv.ReleaseDispatch();

   // Since the dialog has been closed, return FALSE so that we exit the
   //  application, rather than start the application's message pump.
   return FALSE;
}

int CMyTestApp::ExitInstance()
{
// TODO: Add your specialized code here and/or call the base class
  if(pMyEvents)
  {
    delete pMyEvents;
    pMyEvents = NULL;
  }
  MyDrv.ReleaseDispatch();
   
  return CWinApp::ExitInstance();
}


В h файле следующее:
Цитата

//-------------------- My Driver OLE Interface Functions -------------------

 //=================  Driver & devices control Interface  ================
  //============================  Names  =============================
const TCHAR szMyControlObject[]=_T("MyDrv.Control");
const TCHAR szMyControlObjectName[]=_T("My Driver Control");
const TCHAR szMyControlInterface[]=_T("IMyControl");

  ////////////////////////////////////////////////////////////////////
  // CMyControl wrapper class

class CMyControl : public COleDispatchDriver
{
public:
 CMyControl():iShowMessages(false),iParentClosing(false) {Init();}
 CMyControl(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch)
                ,iShowMessages(false)
                ,iParentClosing(false) {Init();}
 CMyControl(const CMyControl& dispatchSrc) :
   COleDispatchDriver(dispatchSrc) {Init();}

// DISPID managing
enum MethodIdxs{
 MyIdx_RegisterClientHwnd,
.....
 MyIdx_SetProtocolParam,
 NumMethods
};
// Overrides
 BOOL CreateDispatch(LPCTSTR lpszProgID,COleException* pError = NULL ){
   BOOL boRet=COleDispatchDriver::CreateDispatch(lpszProgID,pError);
   if(boRet){
     ServerName=lpszProgID;
   }
   return boRet;
 };

// Methods
 int ParentClosing(int iClosing)
 {
  int iRet=iParentClosing;
  iParentClosing=iClosing;
  return iRet;
 };

 HRESULT QueryIds(void);

protected:
 int     iShowMessages;
 int     iParentClosing;
 CString ServerName;

 long    GetMethodId(int iMethodIdx,DISPID *pDispId);
 long    ExceptionHandler(CException* e);
 void    Init(){
           memset(MethodIds,0,sizeof(MethodIds));
         }

public:

// Dispatch Methods

 //============================  Common  ==============================

.....


}; // END OF of class CMyControl


Большая часть этого кода была сгенерирована автоматом. К сожалению этим проектом я не занимался уже более двух лет, и поэтому больше ничем помочь сейчас не смогу. Некоторые функции и переменные являются моими, но они не должны помешать разобраться в сущности
Записан
Oleg I
Гость
« Ответ #16 : 02-12-2004 16:36 » 

SSW: См. в личке.
Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #17 : 02-12-2004 16:53 » 

SSW, вот нашел в книжке про флаги
REGCLS_SINGLEUSE - когда приходит второй активационный запрос СОМ должна использовать другой зарегистрированный обект класса
REGCLS_MULTYPLEUSE - показывает что обект класса может быть использован многократно
так что ищи где у тебя выставляются эти флаги  Ага имхо
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
PSD
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 03-12-2004 06:19 » 

Немного отвлеку от великого и могучего С, в VB реализованы 2 функции для работы с COM

Аналогия следующая
1) CreateObject -> CreateDispatch
2) GetObject -> AttachDispatch
Но GetObject берет в качестве параметров имя класса... может стоит посмотреть как он реализован?
Записан

Да да нет нет все остальное от лукавого.
SSW
Гость
« Ответ #19 : 06-12-2004 13:30 » 

Оказывается эта штука должна работать как Connection Point. При чем этим я облегчаю себе задачу в создании проекта почти на 80%. Я нашел пример с ДЛЛ. Хотел переделать на ЕХЕ. Оказывается общение по интерфейсам между процесами делается по другому нежели между потоками.

Вот когда делаю так, то в принцыпе запускается одна копия приложения сервера.
Хотя это приемлемо для ДЛЛ, но между процесами тоже работает, но все равно как-то криво...
Код:
private:
IMyInterfacePtr m_MyInterface;
DWORD m_dwCookie;


Код:
	EnableAutomation();	
UUID uuid;
m_MyInterface = NULL;

uuid = __uuidof(MyInterface);
m_MyInterface.CreateInstance(uuid);

m_dwCookie = 0;
BOOL Ret = AfxConnectionAdvise(
   m_MyInterface,
   DIID_IFireEvents,
   this->GetIDispatch(FALSE), //get the IDispatch assocaiated with Mainframe...
   FALSE, //donod addref
   &m_dwCookie );//cookie to break connection later...

Может кто знает как реализовать Connection Point между процесами с использованием MFC?

Иначе прийдется разбираться с ATL...
Подскажите где книжки скачать хорошие по ATL.
« Последнее редактирование: 02-12-2007 18:56 от Алексей1153++ » Записан
Pu
Большой босс

ru
Offline Offline
78


« Ответ #20 : 06-12-2004 14:59 » 

SSW, здесь по моему в библиотеке есть - СОМ inside
и еще поищи Трельсена - модель СОМ и применение ATL 3.0
Записан

Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать.
(с) Артур Джонс
SSW
Гость
« Ответ #21 : 07-12-2004 08:04 » 

СОМ inside я уже скачал и посмотрел. А есть у кого нибудь компакт к этой книжке?
Записан
GlukSoft
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 07-12-2004 08:57 » 

SSW, есть 1,47Mb
Записан

Fatal error C1: Brain expected
GlukSoft
Главный специалист

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 07-12-2004 10:36 » new

SSW, лови
Записан

Fatal error C1: Brain expected
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines