Delphi и COM
f65d50f6

Инициализация COM


Каким же образом клиенты и серверы COM могут создавать «комнаты» в соответствии со своими требованиями? Для этого они должны соблюдать одно правило: каждый поток, желающий использовать COM, должен создать «комнату» при помощи вызова функции CoInitializeEx. Она объявлена в модуле ActiveX.pas следующим образом:

const   COINIT_MULTITHREADED      = 0;  // OLE calls objects on any thread.   COINIT_APARTMENTTHREADED  = 2;  // Apartment model function CoInitializeEx(pvReserved: Pointer;                         coInit: Longint): HResult; stdcall;

Параметр pvReserved зарезервирован  для будущего использования и должен быть равен NIL, а параметр coInit определяет потоковую модель создаваемой комнаты. Он может принимать следующие значения:

 



COINIT_APARTMENTTHREADED — для потока создается STA. Каждый поток может иметь (или не иметь) свою STA;
COINIT_MULTITHREADED       — если в текущем процессе еще не создана MTA, создается новая MTA; если она уже создана другим потоком, поток «подключается» к ранее созданной. Иными словами, каждый процесс может иметь только одну MTA.

 

Функция возвращает S_OK в случае успешного создания «комнаты».

По завершении работы с COM (или перед завершением работы) поток должен уничтожить «комнату» при помощи вызова процедуры CoUninitialize, также описанной в модуле ActiveX:

procedure CoUninitialize; stdcall;

Каждый вызов CoInitializeEx  должен иметь соответствующий вызов CoUninitialize, то есть, используя COM в приложении, необходимо вызвать CoInitializeEx до первого использования функций COM и CoUninitialize перед завершением работы приложения. VCL реализует автоматическую инициализацию COM при использовании модуля ComObj. По умолчанию создается STA. При желании необходимость использовать другую потоковую модель следует установить флаг инициализации COM до оператора Application.Initialize:

program Project1; uses   Forms,   ComObj,   ActiveX,   Unit1 in 'Unit1.pas' {Form1}; {$R *.RES} begin   CoInitFlags := COINIT_MULTITHREADED;   Application.Initialize;   Application.CreateForm(TForm1, Form1);   Application.Run; end.

Если COM используется в потоке, то эти функции должны быть вызваны в методе Execute:

procedure TMyThread.Execute; begin   CoInitializeEx(NIL, COINIT_MULTITHREADED);   …   CoUninitialize end;

Инициализация COM необходима и для вызова любых функций Windows API, связанных с COM, за исключением CoGetMalloc, CoTaskMemAlloc, CoTaskMemFree и CoTaskMemReAlloc.

 

Отдельного обсуждения заслуживает инициализация потоковой модели COM для сервера, расположенного в DLL. Дело в том, что DLL может быть загружена любым потоком, который уже ранее создал свою «комнату». Поэтому сервер в DLL не может сам инициализировать требуемую ему потоковую модель. Вместо этого сервер при регистрации прописывает в реестре параметр ThreadingModel, который и указывает, в какой потоковой модели способен работать данный сервер. При создании сервера COM анализирует значение этого параметра и потоковой модели «комнаты» запросившего создание сервера потока и при необходимости создает для сервера «комнату» с требуемой потоковой моделью.

Параметр ThreadingModel может принимать следующие значения:

 

Apartment — сервер может работать только в STA. Если он создается из STA, то он будет создан в «комнате» вызывающего потока, если из MTA — COM автоматически создаст для него «комнату» c STA и proxy в «комнате» клиента;
Free — сервер может работать только в MTA. Если он создается из MTA, то он будет создан в «комнате» вызывающего потока, если из STA — COM автоматически создаст для него «комнату» c MTA и proxy в «комнате» клиента;
Both — сервер может работать как в STA, так и MTA. Объект всегда создается в вызывающей «комнате».

 

Если этот параметр не задан, сервер имеет потоковую модель Single. В этом случае он создается в Primary STA (то есть в STA потока, который первым вызвал CoInitialize), даже если создание сервера запрошено из потока, имеющего свою отдельную STA.



Содержание раздела