SSW
Гость
|
|
« : 01-12-2004 14:37 » |
|
Windows / VC++ 6.0 / MFC Надо создать две программы: сервер и клиент. Клиент отправляет параметры функции которая на сервере, и та выполняет свою работу. Результат возвращает клиенту. Сервер начал делать как обычный проект на основе диалога, добавив при создании галочку Automation. Что доло возможность легко работать с интерфейсами. Потом создание функции, функцию в поток, общение с клиентом... и т.д. и т.п. Клиент - обычный проект на диалоге. В котором добавлен клас, как работать с итерфейсом. И вот, проблема. При запуске клиента запускается сервер. class {MyMFCServer : public COleDispatchDriver 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
|
|
« Ответ #1 : 01-12-2004 15:43 » |
|
Насколько я знаю, это делается с помощью мьютексов... 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
Главный специалист
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
Большой босс
Offline
78
|
|
« Ответ #5 : 02-12-2004 08:53 » |
|
SSW, не надо никаких мутехов, щас пару сек посмотрю как это делается
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #6 : 02-12-2004 09:15 » |
|
короче . надо просто регистрировать класс сервера с флагами REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED. и усе. сервер должен будет запуститься один раз и все последующие вызовы будут на него же. вроде все.
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
SSW
Гость
|
|
« Ответ #7 : 02-12-2004 09:45 » |
|
Чето я немогу найти где их зарегистрировать. :oops:
|
|
|
Записан
|
|
|
|
Pu
Большой босс
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
Большой босс
Offline
78
|
|
« Ответ #10 : 02-12-2004 10:30 » |
|
SSW, смотри функцию аналог main в ней должен быть вызов функции регистрирующей класс. А CoRegisterClassObject спрятана в мфс
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
SSW
Гость
|
|
« Ответ #11 : 02-12-2004 12:21 » |
|
Ты имеешь в виду
BOOL CMyMFCServerApp::InitInstance()
|
|
|
Записан
|
|
|
|
Pu
Большой босс
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
Большой босс
Offline
78
|
|
« Ответ #17 : 02-12-2004 16:53 » |
|
SSW, вот нашел в книжке про флаги REGCLS_SINGLEUSE - когда приходит второй активационный запрос СОМ должна использовать другой зарегистрированный обект класса REGCLS_MULTYPLEUSE - показывает что обект класса может быть использован многократно так что ищи где у тебя выставляются эти флаги имхо
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
PSD
Главный специалист
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
Большой босс
Offline
78
|
|
« Ответ #20 : 06-12-2004 14:59 » |
|
SSW, здесь по моему в библиотеке есть - СОМ inside и еще поищи Трельсена - модель СОМ и применение ATL 3.0
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
SSW
Гость
|
|
« Ответ #21 : 07-12-2004 08:04 » |
|
СОМ inside я уже скачал и посмотрел. А есть у кого нибудь компакт к этой книжке?
|
|
|
Записан
|
|
|
|
GlukSoft
Главный специалист
Offline
Пол:
|
|
« Ответ #22 : 07-12-2004 08:57 » |
|
SSW, есть 1,47Mb
|
|
|
Записан
|
Fatal error C1: Brain expected
|
|
|
GlukSoft
Главный специалист
Offline
Пол:
|
|
« Ответ #23 : 07-12-2004 10:36 » |
|
SSW, лови
|
|
|
Записан
|
Fatal error C1: Brain expected
|
|
|
|