Сущность технологии COM



         

Маршалер свободной поточной обработки (FreeThreaded Marshaler) - часть 5


Если бы класс Point также использовал FTM, то формально это не было бы проблемой. Тем не менее, в общем случае клиенты (такие, так класс Rect), не должны делать допущений относительно этой специфической исключительно для реализаций детали. Фактически, если объекты Point не используют FTM и окажутся созданными в другом апартаменте из-за несовместимости с ThreadingModel, то в этом случае объект Rect содержал бы указатели на заместители. Известно, что заместители четко следуют правилам СОМ и послушно возвращают RPC_E_WRONG_THREAD в тех случаях, когда к ним обращаются из недопустимого апартамента.

Это оставляет разработчику Rect выбор между двумя возможностями. Одна из них — не использовать FTM и просто принять к сведению, что когда клиенты передают объектные ссылки Rect между апартаментами, то для обращения к экземплярам класса Rect будет использоваться ORPC. Это действительно является простейшим решением, так как оно не добавляет никакого дополнительного кода и будет работать, не требуя умственных усилий. Другая возможность - не содержать исходные интерфейсные указатели как элементы данных, а вместо этого держать в качестве элементов данных некую маршалированную форму интерфейсного указателя. Именно для этого и предназначена глобальная интерфейсная таблица (Global Interface Table - GIT). Для реализации данного подхода в классе Rect следовало бы иметь в качестве элементов данных не исходные интерфейсные указатели, а "закладку" (cookies) DWORD:

class SafeRect : public IRect { LONG m_cRef; // СОМ reference count // счетчик ссылок СОМ IUnknown *m_pUnkFTM; // cache for FTM lazy aggregate // кэш для отложенного агрегирования FTM DWORD m_dwTopLeft; // GIT cookie for top/left // закладка GIT для верхнего/левого DWORD m_dwBottomR1ght; // GIT cookie for bottom/right // закладка GIT для нижнего/правого

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

SafeRect::SafeRect(void) : m_cRef(0), m_pUnkFTM(0) { // assume ptr to GIT is initialized elsewhere // допустим, что указатель на GIT инициализирован // где-нибудь в другом месте extern IGIobalInterfaceTable *g_pGIT; assert(g_pGIT != 0); IPoint *pPoint = 0; // create instance of class Point // создаем экземпляр класса Point HRESULT hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&pPoint); assert (SUCCEEDED (hr)); // register interface pointer in GIT // регистрируем интерфейсный указатель в GIT hr = g_pGIT->RegisterInterfaceInGlobal(pPoint, IID_Ipoint, &m_dwTopLeft); assert(SUCCEEDED(hr)); pPoint->Release(); // reference is now held in GIT // ссылка теперь содержится в GIT




Содержание  Назад  Вперед