Суть проблемы такая (возможно, ниже я немного буду путаться в терминах — не судите строго):
(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