Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 CreateComObject и фабрика класса  [new]
verter
Member

Откуда: Санкт-Петербург
Сообщений: 899
Помогите, пожалуйста, разобраться.

Есть проект локального COM-сервера в виде exe-файла.
В главном юните проекта где расположен коклас реализующий интерфейс в секции initialization создаётся объект фабрики класса для создания COM-объекта сервера:

TComponentFactory.Create(ComServer,имя кокласса,CLSID кокласса,ciSingleInstance,tmFree);

На клиенте создание COM-объекта происходит с помощью вызова стандартной функции Delphi CreateComObject из юнита ComObj:

CreateComObject(CLSID кокласса);

Я не могу понять кто в итоге создаёт COM-объект? Вернее, как именно он создаётся? С использованием этой фабрики класса
TComponentFactory или нет? Ну т.е. когда происходит вызов функции CreateComObject, то как то потом неявно вызывается ли метод указанной фабрики класса, который уже в свою очередь создаёт этот COM-объект?
3 окт 17, 18:37    [20840019]     Ответить | Цитировать Сообщить модератору
 Re: CreateComObject и фабрика класса  [new]
Aniskin
Member

Откуда:
Сообщений: 227
Грубое описание.

При регистрации сервер добавляет ключ реестра HKEY_CLASSES_ROOT\CLSID\{CLSID}\LocalServer32, где прописан путь до exe файла самого сервера. Когда клиент вызывает CreateComObject(CLSID), то COM система читает из реестра этот путь и запускает exe файл на исполнение и ждет кое-чего (об это ниже). При запуске COM сервер создает фабрику TComponentFactory.Create, сама фабрика внутри себя вызывает CoRegisterClassObject(CLSID). Имеено этого и ждет COM система (если не ошибаюсь, максимум 5 минут). После регистрации происходят вызовы методов зарегистрированной фабрики и создание экземпляра самого сервера. Ссылка на сервер готова, выход из CreateComObject.
3 окт 17, 23:08    [20840496]     Ответить | Цитировать Сообщить модератору
 Re: CreateComObject и фабрика класса  [new]
verter
Member

Откуда: Санкт-Петербург
Сообщений: 899
Aniskin
Грубое описание.

При регистрации сервер добавляет ключ реестра HKEY_CLASSES_ROOT\CLSID\{CLSID}\LocalServer32, где прописан путь до exe файла самого сервера. Когда клиент вызывает CreateComObject(CLSID), то COM система читает из реестра этот путь и запускает exe файл на исполнение и ждет кое-чего (об это ниже). При запуске COM сервер создает фабрику TComponentFactory.Create, сама фабрика внутри себя вызывает CoRegisterClassObject(CLSID). Имеено этого и ждет COM система (если не ошибаюсь, максимум 5 минут). После регистрации происходят вызовы методов зарегистрированной фабрики и создание экземпляра самого сервера. Ссылка на сервер готова, выход из CreateComObject.


Огромное спасибо! Теперь всё встало на свои места. Остался единственный непонятный момент:

вот вы пишите, что COM система после вызова клиентом CreateComObject(CLSID) запускает exe файл COM сервера на исполнение по пути указанному в реестре, т.е. получается уже создаётся экземпляр сервера. А потом вы пишите, что после того как фабрика будет создана и зарегистрирована, то будет создан экземпляра самого сервера. Вы имеете ввиду будет создан экземпляр кокласса, т.е. COM-объект? Или всё-таки будет запущен exe-файл COM-сервера в соответствии c указанным в конструкторе фабрики значением параметра Instancing = ciSingleInstance или ciMultiInstance. Ведь в зависимости от этого значения будет запущен или отдельный процесс сервера или увеличена ссылка на тот же процесс.
4 окт 17, 12:23    [20841674]     Ответить | Цитировать Сообщить модератору
 Re: CreateComObject и фабрика класса  [new]
Aniskin
Member

Откуда:
Сообщений: 227
Еще одно грубое описание.

У COM системы есть глобальная общая на все процессы таблица, в которой есть 4 поля: CLSID, ссылка на фабрику, флаги фабрики, ссылка на объект. Именно в эту таблицу происходит запись информации при вызове фабрикой функции CoRegisterClassObject. Флаги, которые нас интересуют - REGCLS_SINGLEUSE и REGCLS_MULTIPLEUSE, которые соответствуют ciSingleInstance и ciMultiInstance соответственно.

CreateComObject вызывает CoCreateInstance, которая анализирует эту табличку последовательно перебирая все строки таблицы. Если в в текущей строке таблицы CLSID равен запрашиваемому CLSID, то проверяется ссылка на объект. Если ссылки нет, то вызываются методы фабрики и создается объект сервера, ссылка на объект заносится в таблицу, выход. Если ссылка есть, то анализируются флаги. Если выставлен флаг REGCLS_MULTIPLEUSE, то берется существующая ссылка на объект и происходит выход. Если выставлен флаг REGCLS_SINGLEUSE, то текущая запись таблицы пропускается.

Если при поиске не найдена подходящая запись, то происходит происходит создание нового процесса по ключу в реестре и ожидание. Новый процесс для каждой фабрики вызывает CoRegisterClassObject. Когда COM система увидела новые записи в таблице, то она повторяет поиск в таблице с учетом новых строк.

Псевдокод:

function CoCreateInstance(const CLSID: TGUID): IUnknown;
var
  Index: Integer;
begin
  while True do
    begin
      for Index := 0 to GlobalTable.Count - 1 do
        if GlobalTable[Index].CLSID = CLSID then
          if not Assigned(GlobalTable[Index].Obj) then
            begin
              GlobalTable[Index].Obj := GlobalTable[Index].Factory.CreateObj;
              Result := GlobalTable[Index].Obj;
              Exit;
            end
          else
            if GlobalTable[Index].Flags and REGCLS_MULTIPLEUSE <> 0 then
              begin
                Result := GlobalTable[Index].Obj;
                Exit;
              end;

      ReadRegistryAndCreateNewProcess;
      WaitForFactoryRegistration;
    end;
end;

function CoRegisterClassObject(const CLSID: TGUID; AFactory: IUnknown; AFlags: DWORD): Integer;
begin
  Result := GlobalTable.Add(CLSID, AFactory, AFlags);
end;
4 окт 17, 14:43    [20842324]     Ответить | Цитировать Сообщить модератору
 Re: CreateComObject и фабрика класса  [new]
verter
Member

Откуда: Санкт-Петербург
Сообщений: 899
Aniskin,

теперь всё понятно, ещё раз большое спасибо!
4 окт 17, 15:29    [20842536]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить