Есть вопрос по взаимодействию com-объекта и клиента
От: Relder Россия  
Дата: 02.08.06 11:35
Оценка:
Суть проблемы такая (возможно, ниже я немного буду путаться в терминах — не судите строго):

(1) Есть com-объект (точнее, приложение-сервер автоматизации, допустим он обзывается MyOwnOnject), который желательно иметь при работе в _единственном_ экземпляре и связанного с единственным клиентом (то есть, в памяти сидит _один_ клиент, который и получает с этого объекта данные).

Я так понимаю, что единственность указывается таким вызовом? (в секции initialization — пишу я это все на Delphi):


TAutoObjectFactory.Create(ComServer, MyOwnObject_Auto, Class_MyOwnObject_Auto,
                          ciSingleInstance, tmApartment);


Или для этого нужно что-то еще?

Пока что у меня получилась модель такая: к одному серверу могут прицепиться несколько клиентов (что не хотелось бы!), все они могут вызывать методы
сервера, но получает от сервера сообщения только один (первый присоединившийся) клиент. Как-то мне это не нравится.



(2) Как быть в том случае, если клиент аварийно прекратил работу (а сервер остался в памяти в блаженном неведении о смерти своего клиента)? При запуске
нового клиента, присоединить его к серверу не получается (точнее, клиент может вызывать методы сервера, но не получает от сервера сообщения, каковые, полагаю, адресуются "первому клиенту", уже помершему).

Как вариант (очень кривой, я в курсе), попробовал такую связку:


var
  ActiveObj: IUnknown;  TheWindow : HWND;
  ProcessID: Integer;   ProcessHandle : THandle;

 * * *

  GetActiveObject (CLASS_MyOwnObject_Auto, nil, ActiveObj);
  if ActiveObj <> nil then
  begin
    TheWindow := FindWindow('TFormMyOwnObject', nil);
    GetWindowThreadProcessID(TheWindow, @ProcessID);
    ProcessHandle := OpenProcess(PROCESS_TERMINATE, FALSE, ProcessId);
    TerminateProcess(ProcessHandle,4);
    CloseHandle(ProcessHandle);
    FServer := CoMyOwnObject_Auto.Create;
  end
  else
    FServer := CoMyOwnObject_Auto.Create;


или, допускаю более "цивилизованный" вариант, заменить секцию с вызовом TerminateProcess на

  PostMessage(FindWindow('TFormMyOwnObject', nil), WM_QUIT, 0, 0);


(и уже потом вызов CoMyOwnObject_Auto.Create),

добавив в сервер процедуру отлова сообщения WM_QUIT, в каковой процедуре можно сделать необходимые действия (сбросить файлы, погасить транзакции, etc.) и завершить работу сервера.

Hо!

(a) Как мне завершить работу сервера из него самого, когда у него уже есть "нить" (???) связывающая его с "первым" (умершим) клиентом? Простые методы типа Application.Terminate не действуют, так как как он начинает жаловаться, мол "There are still active COM objects in this application", выводить менюшки и прочее. Хотя, конечно, можно попробовать "самоубиваться" через TerminateProcess (а самого себя так можно убить?).

(b) И как мне вообще узнать (изнутри сервера) — задействован ли сервер в данный момент или свободен?

(с) И как можно (изнутри сервера, при условии положительных ответов на вопросы a и b) разорвать эту "нить"?



(3) К слову, в Win XP кусок кода с TerminateProcess у меня работал "на ура". А в Win98 — уже как-то не хочет. Я пока не разбирался углубленно (нету у меня под 98'ми установленного Delphi, пошагово не пройдешь), но нет ли тут уже каких-то известных подводных камней?




Заранее спасибо. Буду благодарен за любую помощь, включая и предметные ссылки на RTFM (я вообще, не вполне хорошо ориентируюсь в com-технологии), хотя,
конечно, более детальные ответы были бы для меня совсем щастьем!

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