Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> C/C++ -> Сущность технологии COM


Моникеры и сохраняемость

Обсуждение моникеров не может быть полным без обсуждения файлового моникера (File Moniker). Напомним, что СОМ предусматривает три примитива активации: привязывание к объектам класса, привязывание к новым экземплярам класса и привязывание к постоянным объектам, хранящимся в файлах. В данной главе детально анализировались первые два из этих примитивов. Третий примитив основан на API-функции СОМ CoGetInstanceFromFile:

HRESULT CoGetInstanceFromFile( 
          [in, unique] COSERVERINFO *pcsi,
            // host/security info - информация о хосте/безопасности 
          [in, unique] CLSID *pClsid,
            // explicit CLSID (opt) - явный CLSID (opt)
          [in, unique] IUnknown *punk0uter, 
            // for aggregation - для агрегирования 
          [in] DWORD dwClsCtx,
            // locality? - локализация?
          [in] DWORD grfMode,
            // file open mode - режим открытия файла 
          [in] OLECHAR *pwszName,
            // file name of object - файловое имя объекта 
          [in] DWORD cmqi,
            // how many interfaces? - сколько интерфейсов? 
          [out, size_is(cmqi)] MULTI_QI *prgmq
            // where to put itfs - куда поместить интерфейсы
);

Эта функция принимает на вход имя файла, которое относится к постоянному состоянию (persistent state) объекта1. CoGetInstanceFromFile удостоверяется в том, что объект исполняется, после чего возвращает один или несколько интерфейсных указателей на (ре)активированный объект. Чтобы выполнить эту работу, CoGetInstanceFromFile в первую очередь требуется определить CLSID данного объекта. CLSID требуется по двум причинам. Если объект не исполняется, то CLSID необходим СОМ для создания нового экземпляра, который будет инициализирован от постоянного (находящегося в файле) образа. Во-вторых, если вызывающий объект не указывает определенное хост-имя до запроса на активацию, то СОМ будет использовать CLSID для выяснения того, на какой машине следует активировать объект2.

Если CLSID не передается явно вызывающим объектом, то CoGetInstanceFromFile извлекает CLSID из самого файла с помощью вызова API-функции СОМ GetClassFile:

HRESULT GetClassFile([in, string) OLECHAR *pwszFileName, [out] CLSID *pclsid);

Для определения типа объекта, содержащегося в файле, GetClassFile использует информацию из заголовка файла, а также информацию из реестра.

После того как определены класс и хост-машина, СОМ исследует ROT (Running Object Table - таблица исполняющихся объектов) на целевой хост-машине для того, чтобы выяснить, является ли объект уже активированным. Таблица ROT является инструментом SCM, который преобразует произвольные моникеры в экземпляры объектов, исполняющихся на локальной хост-машине. Ожидается, что постоянные объекты будут регистрировать себя в локальной ROT во время загрузки. Чтобы представить файловое имя постоянного объекта в качестве моникера, СОМ предусматривает стандартный тип моникера - файловый моникер, который оборачивает имя файла в интерфейс IMoniker. Файловые моникеры могут создаваться либо путем передачи файлового имени в МkParseDisplayName, либо вызовом явной API-функции CreateFileMoniker:

HRESULT CreateFileMoniker(
          [in, string] const OLECHAR *pszFileName, 
          [out] IMoniker **ppmk);

Если постоянный объект уже зарегистрировал в ROT свой файловый моникер, то CoGetInstanceFromFile просто возвращает указатель на уже работающий объект. Если же объект в ROT не найден, то СОМ создает новый экземпляр файлового класса и инициализирует его из постоянного объекта с помощью метода IPersistFile::Load этого экземпляра:

[object, uuid(0000010b-0000-0000-C000-000000000046)]
interface IPersistFile : IPersist {
  // called by CoGetInstanceFromFile to initialize object
  // вызывается функцией CoGetInstanceFromFile для
  // инициализации объекта
  HRESULT Load(
            [in, string] const OLECHAR * pszFileName,
            [in] DWORD grfMode );
  // remaining methods deleted for clarity 
  // остальные методы удалены для ясности
}

Реализация объекта отвечает за загрузку из файла всех постоянных элементов и за саморегистрацию в локальной таблице ROT - с целью убедиться, что для каждого файла в каждый момент может исполняться только один экземпляр:

STDMETHODIMP::Load(const OLECHAR *pszFileName, DWORD grfMode)
{
      // read in persisted object state 
      // считываем сохраненное состояние объекта 
    HRESULT hr = this->MyReadStateFromFile(pszFile, grfMode);
    if (FAILED(hr)) 
        return hr;
      // get pointer to ROT from SCM 
      // берем указатель на ROT от SCM 
    IRunningObjectTable *prot = 0;
    hr = GetRunningObjectTable(0, &prot);
    if (SUCCEEDED(hr)) {
          // create a file moniker to register in ROT
          // создаем файловый моникер для регистрации в ROT
        IMoniker *pmk = 0;
        hr = CreateFileMoniker(pszFileName, &pmk);
        if (SUCCEEDED(hr)) {
              // register self in ROT
              // саморегистрация в ROT
            hr = prot->Register(0, this, pmk, &m_dwReg);
            pmk->Release();
        }
        prot->Release();
    }
    return hr;
}

Метод IPersistFile::Load нового созданного экземпляра будет вызван диспетчером SCM во время выполнения CoGetInstanceFromFile. В приведенном выше примере для получения указателя на интерфейс IRunningObjectTable в SCM используется API-функция СОМ GetRunningObjectTable. Этот интерфейс затем используется для регистрации своего моникера в ROT, так что последующие вызовы CoGetInstanceFromFile, использующие то же файловое имя, не будут создавать новые объекты, а вместо этого возвратят ссылки на этот объект3.

Существование File Moniker обусловлено двумя причинами. Во-первых, он нужен, чтобы позволить объектам самим регистрироваться в ROT, чтобы их мог найти CoGetInstanceFromFile. Во-вторых, чтобы скрыть от клиента использование CoGetInstanceFromFile за интерфейсом IMoniker. Реализация File Moniker из BindToObject просто вызывает CoGetInstanceFromFile:

// pseudo-code from OLE32.DLL 
// псевдокод из OLE32.DLL

STDMETHODIMP FileMoniker::BindToObject(IBindCtx *pbc, 
                                       IMoniker *pmkToLeft, 
                                       REFIID riid, void **ppv) 
{
      // assume failure - на случай сбоя 
    *ppv = О;
    HRESULT hr = E_FAIL;
    if (pmkToLeft == 0) {
          // no moniker to left - слева моникеров нет
        MULTI_QI mqi = { &riid, 0, 0 };
        COSERVERINFO *pcsi;
        DWORD grfMode;
        DWORD dwClsCtx;
          // these three parameters are attributes of the BindCtx 
          // эти три параметра являются атрибутами BindCtx 
        this->MyGetFromBindCtx(pbc, &pcsi, &grfMode, &dwClsCtx);
        hr = CoGetInstanceFromFile(pcsi, 0, 0, dwClsCtx,
                                   grfMode, this->m_pszFileName, 
                                   1, &mqi);
        if (SUCCEEDED(hr))
            *ppv = mqi.pItf;
    } else {
          // there's a moniker to the left - слева есть моникер 
          // ask object to left for IClassActivator 
          // or IClassFactory
          // запрашиваем объект слева от IClassActivator или от 
          // IClassFactory 
    } 
    return hr;
}

При таком поведении File Moniker следующая функция, вызывающая CoGetInstanceFromFile

HRESULT GetCornelius(IApe * &rpApe) 
{
    OLECHAR *pwszObject = 
        OLESTR("\\\\server\\public\\cornelius.chmp");
    MULTI_QI mqi = { &IID_IApe, 0, 0 };
    HRESULT hr = CoGetInstanceFromFile(0, 0, 0, CLSCTX_SERVER, 
                   STCM_READWRITE, pwszObject, 1, &mqi);
    if (SUCCEEDED(hr)) rpApe = mqi.pItf;
    else 
      rpApe = 0;
    return hr;
}

может быть упрощена, если вместо этого использовать вызов CoGetObject:

HRESULT GetCornelius(IApe * &rpApe)
{
    OLECHAR *pwszObject = OLESTR("\\\\server\\public\\cornelius.chmp");
    return CoGetObject(pwszObject, 0, IID_IApe, (void**)&rpApe);
}

Как и в предыдущем случае, когда использовался Class Moniker, уровень изоляции, обеспеченный CoGetObject, позволяет клиенту задавать сколь угодно сложную стратегию активации, не меняя ни единой строки кода.


1 Альтернативная версия этой API-функции. CoGetInstanceFromIStorage, вместо имени файла принимает указатель на иерархическое хранилище (storage medium).

2 В дополнение к обычной переадресации CLSID на хост-машины, которое используется функциями CoGetClassObject/CoCreateInstanceEx, CoGetInstanceFromFile может использовать в качестве имени файла UNC-имя хоста (universal naming convention - общее соглашение по именам), чтобы переадресовать запрос на активацию на ту хост-машину, где расположен данный файл. Этот режим активации упоминается в Спецификации СОМ как побитовая активация ("AtВits" activation) и описывается с использованием установок реестра "ActivateAtStorage", как описано в главе 6.

3 На практике областью действия ROT является не вся машина, а только Winstation. Это означает, что по умолчанию не все зарегистрированные сессии (logon sessions) получат доступ к объекту. Чтобы убедиться, что объект является видимым для всех возможных клиентов, при вызове IRunningObjectTable::Register объект должен выставить флаг ROTFLAGS_ALLOWANYCLIENT.

Время жизни сервера
Классы и IDL
Эмуляция классов
Категории компонентов
Где мы находимся?

 

 
Интересное в сети

https://www.mediccity.ru/directions/412 отит как снять воспаление уха лечение.

 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.