Современная электронная библиотека ModernLib.Net

Сущность технологии СОМ. Библиотека программиста

ModernLib.Net / Программирование / Бокс Дональд / Сущность технологии СОМ. Библиотека программиста - Чтение (стр. 32)
Автор: Бокс Дональд
Жанр: Программирование

 

 


ChatSessionClass::SESSIONMAP &sessions

= pSessionClass->m_sessions;

m_pStrings = new vector;

pSessionClass->Lock();

for (iterator it = sessions.begin();

it != sessions.end();

it++)

{

m_pStrings->push_back((*it).first);

}

pSessionClass->Unlock();

m_cursor = Strings().begin();

InitializeCriticalSection(&m_csLock);

}

SessionNamesEnumerator::SessionNamesEnumerator(

SessionNamesEnumerator *pCloneSource)

: m_cRef(0),

m_pStrings(0),

m_pCloneSource(pCloneSource)

{

m_pCloneSource->AddRef();

m_cursor = Strings().begin();

InitializeCriticalSection(&m_csLock);

}

SessionNamesEnumerator::~SessionNamesEnumerator(void)

{

if (m_pCloneSource)

m_pCloneSource->Release();

else if (m_pStrings)

delete m_pStrings;

DeleteCriticalSection(&m_csLock);

}

// IUnknown methods

STDMETHODIMP

SessionNamesEnumerator::QueryInterface(REFIID riid, void **ppv)

{

if (riid == IID_IUnknown)

*ppv = static_cast(this);

else if (riid == IID_IEnumString)

*ppv = static_cast(this);

else

return (*ppv = 0), E_NOINTERFACE;

reinterpret_cast(*ppv)->AddRef();

return S_OK;

}

STDMETHODIMP_(ULONG)

SessionNamesEnumerator::AddRef(void)

{

ModuleLock();

return InterlockedIncrement(&m_cRef);

}

STDMETHODIMP_(ULONG)

SessionNamesEnumerator::Release(void)

{

LONG res = InterlockedDecrement(&m_cRef);

if (res == 0)

delete this;

ModuleUnlock();

return res;

}

// IEnumString methods

STDMETHODIMP

SessionNamesEnumerator::Next(ULONG cElems, OLECHAR **rgElems,

ULONG *pcFetched)

{

if (cElems > 1 && pcFetched == 0)

return E_INVALIDARG;

ULONG cActual = 0;

vector &rstrings = Strings();

Lock();

while (cActual < cElems

&& m_cursor != rstrings.end())

{

if (rgElems[cActual] = OLESTRDUP((*m_cursor).c_str()))

{

m_cursor++;

cActual++;

}

else // allocation error, unwind

{

while (cActual > 0)

{

cActual–;

CoTaskMemFree(rgElems[cActual]);

rgElems[cActual] = 0;

}

break;

}

}

Unlock();

if (cActual)

*pcFetched = cActual;

return cActual == cElems ? S_OK : S_FALSE;

}

STDMETHODIMP

SessionNamesEnumerator::Skip(ULONG cElems)

{

ULONG cActual = 0;

vector &rstrings = Strings();

Lock();

while (cActual < cElems

&& m_cursor != rstrings.end())

{

m_cursor++;

cActual++;

}

Unlock();

return cActual == cElems ? S_OK : S_FALSE;

}

STDMETHODIMP

SessionNamesEnumerator::Reset(void)

{

Lock();

m_cursor = Strings().begin();

Unlock();

return S_OK;

}

STDMETHODIMP


SessionNamesEnumerator::Clone(IEnumString **ppes)

{

if (ppes == 0)

return E_INVALIDARG;

SessionNamesEnumerator *pCloneSource = m_pCloneSource;

if (pCloneSource == 0) // we are the source

m_pCloneSource = this;

*ppes = new SessionNamesEnumerator(pCloneSource);

if (*ppes)

{

(*ppes)->AddRef();

return S_OK;

}

return E_OUTOFMEMORY;

}

svc.cpp

/////////////////////////////////////////////////////

//

// svc.cpp

//

// Copyright 1997, Don Box/Addison Wesley

//

// This code accompanies the book "The Component

// Object Model" from Addison Wesley. Blah blah blah

//

//

#define _WIN32_WINNT 0x403

#include

#include

#include

#include

#include «ChatSession.h»

#include «../include/COMChat_i.c»


#if !defined(HAVE_IID_IACCESSCONTROL)

// there is a common bug is the SDK headers and libs

// that causes IID_IAccessControl to be undefined.

// We define it here to give the GUID linkage.

DEFINE_GUID(IID_IAccessControl,0xEEDD23E0, 0x8410, 0x11CE,

0xA1, 0xC3, 0x08, 0x00, 0x2B, 0x2B, 0x8D, 0x8F);

#endif

// standard MTA lifetime management helpers

HANDLE g_heventDone = CreateEvent(0, TRUE, FALSE, 0);

void ModuleLock(void)

{

CoAddRefServerProcess();

}

void ModuleUnlock(void)

{

if (CoReleaseServerProcess() == 0)

SetEvent(g_heventDone);

}

// standard self-registration table

const char *g_RegTable[][3] = {

{ «CLSID\\{5223A053-2441-11d1-AF4F-0060976AA886}»,

0, «ChatSession» },

{ «CLSID\\{5223A053-2441-11d1-AF4F-0060976AA886}»,

«AppId», «{5223A054-2441-11d1-AF4F-0060976AA886}»

},

{ «CLSID\\{5223A053-2441-11d1-AF4F-0060976AA886}\\LocalServer32»,

0, (const char*)-1 // rogue value indicating file name

},

{ «AppID\\{5223A054-2441-11d1-AF4F-0060976AA886}»,

0, «ChatSession Server» },

{ «AppID\\{5223A054-2441-11d1-AF4F-0060976AA886}»,

«RunAs», «Domain\\ReplaceMe»

},

{ «AppID\\{5223A054-2441-11d1-AF4F-0060976AA886}»,

«Chat Admins Group», «Domain\\ReplaceMe»

},

{ «AppID\\{5223A054-2441-11d1-AF4F-0060976AA886}»,

«Chat Users Group», «Domain\\ReplaceMe»

},

{ «AppID\\COMChat.exe»,

«AppId», «{5223A054-2441-11d1-AF4F-0060976AA886}»

},

};

// self-unregistration routine

STDAPI UnregisterServer(void) {

HRESULT hr = S_OK;

int nEntries = sizeof(g_RegTable)/sizeof(*g_RegTable);

for (int i = nEntries – 1; i >= 0; i–){

const char *pszKeyName = g_RegTable[i][0];

long err = RegDeleteKeyA(HKEY_CLASSES_ROOT, pszKeyName);

if (err != ERROR_SUCCESS)

hr = S_FALSE;

}

return hr;

}

// self-registration routine

STDAPI RegisterServer(HINSTANCE hInstance = 0) {

HRESULT hr = S_OK;

// look up server's file name

char szFileName[MAX_PATH];

GetModuleFileNameA(hInstance, szFileName, MAX_PATH);

// register entries from table

int nEntries = sizeof(g_RegTable)/sizeof(*g_RegTable);

for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {

const char *pszKeyName = g_RegTable[i][0];

const char *pszValueName = g_RegTable[i][1];

const char *pszValue = g_RegTable[i][2];

// map rogue value to module file name

if (pszValue == (const char*)-1)

pszValue = szFileName;

HKEY hkey;

// create the key

long err = RegCreateKeyA(HKEY_CLASSES_ROOT,

pszKeyName, &hkey);

if (err == ERROR_SUCCESS) {

// set the value

err = RegSetValueExA(hkey, pszValueName, 0,

REG_SZ, (const BYTE*)pszValue,

(strlen(pszValue) + 1));

RegCloseKey(hkey);

}

if (err != ERROR_SUCCESS) {

// if cannot add key or value, back out and fail

UnregisterServer();

hr = SELFREG_E_CLASS;

}

}

return hr;

}

// these point to standard access control objects

// used to protect particular methods

IAccessControl *g_pacUsers = 0;

IAccessControl *g_pacAdmins = 0;

// this routine is called at process init time

// to build access control objects and to allow

// anonymous access to server by default

HRESULT InitializeApplicationSecurity(void)

{

// load groupnames from registry

static OLECHAR wszAdminsGroup[1024];

static OLECHAR wszUsersGroup[1024];

HKEY hkey;

long err = RegOpenKeyEx(HKEY_CLASSES_ROOT,

__TEXT(«AppID\\{5223A054-2441-11d1-AF4F-0060976AA886}»),

0, KEY_QUERY_VALUE,

&hkey);

if (err == ERROR_SUCCESS)

{

DWORD cb = sizeof(wszAdminsGroup);

err = RegQueryValueExW(hkey, L"Chat Admins Group",

0, 0, (BYTE*)wszAdminsGroup,

&cb);

cb = sizeof(wszAdminsGroup);

if (err == ERROR_SUCCESS)

err = RegQueryValueExW(hkey,

L"Chat Users Group",

0, 0, (BYTE*)wszUsersGroup,

&cb);

RegCloseKey(hkey);

}

if (err != ERROR_SUCCESS)

return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,

GetLastError());


// declare vectors of user/groups for 2 access

// control objects

ACTRL_ACCESS_ENTRYW rgaaeUsers[] = {

{ {0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME,

TRUSTEE_IS_GROUP, wszUsersGroup },

ACTRL_ACCESS_ALLOWED, COM_RIGHTS_EXECUTE, 0,

NO_INHERITANCE, 0 },

};

ACTRL_ACCESS_ENTRY_LISTW aaelUsers = {

sizeof(rgaaeUsers)/sizeof(*rgaaeUsers),

rgaaeUsers

};

ACTRL_PROPERTY_ENTRYW apeUsers = { 0, &aaelUsers, 0 };

ACTRL_ACCESSW aaUsers = { 1, &apeUsers };

ACTRL_ACCESS_ENTRYW rgaaeAdmins[] = {

{ {0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME,

TRUSTEE_IS_GROUP, wszAdminsGroup },

ACTRL_ACCESS_ALLOWED, COM_RIGHTS_EXECUTE, 0,

NO_INHERITANCE, 0 },

};

ACTRL_ACCESS_ENTRY_LISTW aaelAdmins = {

sizeof(rgaaeAdmins)/sizeof(*rgaaeAdmins),

rgaaeAdmins

};

ACTRL_PROPERTY_ENTRYW apeAdmins = { 0, &aaelAdmins, 0 };

ACTRL_ACCESSW aaAdmins = { 1, &apeAdmins };

HRESULT hr = CoInitializeSecurity(0, -1, 0, 0,

RPC_C_AUTHN_LEVEL_NONE,

RPC_C_IMP_LEVEL_ANONYMOUS,

0,

EOAC_NONE,

0);

if (SUCCEEDED(hr))

{

hr = CoCreateInstance(CLSID_DCOMAccessControl,

0, CLSCTX_ALL, IID_IAccessControl,

(void**)&g_pacUsers);

if (SUCCEEDED(hr))

hr = g_pacUsers->SetAccessRights(&aaUsers);

if (SUCCEEDED(hr))

{

hr = CoCreateInstance(CLSID_DCOMAccessControl,

0, CLSCTX_ALL,

IID_IAccessControl,

(void**)&g_pacAdmins);

if (SUCCEEDED(hr))

hr = g_pacAdmins->SetAccessRights(&aaAdmins);

}

if (FAILED(hr))

{

if (g_pacAdmins)

{

g_pacAdmins->Release();

g_pacAdmins = 0;

}

if (g_pacUsers)

{

g_pacUsers->Release();

g_pacUsers = 0;

}

}

}

return hr;

}

// the main thread routine that simply registers the class

// object and waits to die

int WINAPI WinMain(HINSTANCE, HINSTANCE,

LPSTR szCmdParam, int)

{

const TCHAR *pszPrompt =

__TEXT("Ensure that you have properly ")

__TEXT("configured the application to ")

__TEXT("run as a particular user and that ")

__TEXT("you have manually changed the ")

__TEXT("Users and Admins Group registry ")

__TEXT(«settings under this server's AppID.»);

HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);

if (FAILED(hr))

return hr;

// look for self-registration flags

if (strstr(szCmdParam, «/UnregServer») != 0

|| strstr(szCmdParam, «-UnregServer») != 0)

{

hr = UnregisterServer();

CoUninitialize();

return hr;

}

else if (strstr(szCmdParam, «/RegServer») != 0

|| strstr(szCmdParam, «-RegServer») != 0)

{

hr = RegisterServer();

MessageBox(0, pszPrompt, __TEXT(«COMChat»),

MB_SETFOREGROUND);

CoUninitialize();

return hr;

}


// set up process security

hr = InitializeApplicationSecurity();

if (SUCCEEDED(hr))

{

// register class object and wait to die

DWORD dwReg;

static ChatSessionClass cmc;

hr = CoRegisterClassObject(CLSID_ChatSession,

static_cast(&cmc),

CLSCTX_LOCAL_SERVER

REGCLS_SUSPENDED|REGCLS_MULTIPLEUSE,

&dwReg);

if (SUCCEEDED(hr))

{

hr = CoResumeClassObjects();

if (SUCCEEDED(hr))

WaitForSingleObject(g_heventDone, INFINITE);

CoRevokeClassObject(dwReg);

}

g_pacUsers->Release();

g_pacAdmins->Release();

}

if (FAILED(hr))

MessageBox(0, pszPrompt, __TEXT(«Error»),

MB_SETFOREGROUND);

CoUninitialize();

return 0;

}


More Book Stuff

Source Code

COM Chat Compilable versions of the source code in Appendix B of the book. 

YACL Yet another COM library. Contains the various macros and C++ classes described in the book. 

IGlobalInterfaceTable Wrapper/Sample A simplification of apartment-independent pointer use. 

HostHook A custom channel hook that allows you to find out the caller's and callee's network address.

APTSUR A custom surrogate that spawns distinct STA threads for each activation request. 

Custom Moniker Stuff I worked with some friends on a custom moniker framework. Here is some of the 1st bits and pieces.


Yet Another COM Library (YACL) – Preview

This is my first drop. It contains a family of preprocessor macros that automate the boilerplate activities used in COM programming.

Please send comments and bug reports to cbbugs@braintrust.com

The freshest drop is always available at http://www.develop.com/dbox/yacl.zip


Design Goals (in Order)

Easily used without Wizard support

Easily kept in one's head

Modular (use only what you need and nothing else)

Extensible

Small Code

Fast Code

No DLL ever

Compiler-friendly

Platform-neutral where possible (including 16-bit Windows)


Current Feature Set

Anal-rententive Smart Pointer

Efficient and intuitive Unicode handling

Table-driven QueryInterface

Table-driven Registration

Table-driven Class management

Generic Class Factory implementation.

Preprocessor macros for de facto IUnknown implementation techniques.

Preprocessor macros for de facto module management routines.

Preprocessor macros for de facto DllXXX routines.

Preprocessor macros for de facto out-of-proc CRCO/Wait/CRCO sequence.


Planned Work

Performance/size tuning

Compiler/Platform testing

Verify ATL/MFC interoperation

Macro-ization of smart pointer for 16-bit windows

Add optional exception semantics to smart pointer

Map COM hresults/exception to C++ exceptions

Add support for IDispatch and friends

Add support for IConnectionPoint and friends

Add IEnum -> stl thunks


1 Исследование Гиги (Giga), порученное ему фирмой Microsoft, показывает, что в 1997 году рынок коммерческих компонентов, основанных на СОМ, составил 410 миллионов долларов. Ожидается, что этот рынок к 2001 году превысит 2.8 миллиарда долларов. Эти цифры не включают продукцию Microsoft.


2 Упражнение для читателя: назовите одну коммерчески доступную объектную систему, кроме СОМ, которая предусматривает двоичное повторное использование, поддерживает жесткое управление версиями, прозрачность адресации и независимость от языка программирования. Если вы скажете: «CORBA», – то вас надули и вы не знаете такой объектной системы.


3 Выдержки из The American Heritage Dictionary of the English Language, Third Edition © 1996 by Houghton Mifflin Company. Электронная версия лицензирована INSO Corporation; дальнейшее копирование и распространение осуществляется в соответствии с законом об авторских правах Соединенных Штатов. Все права защищены.


4 Вспомните речь Билла о IAYF на конгрессе Comdex-1990.


1 В момент написания этого текста автор не имел работающей версии этого алгоритма, годной для публикации. Детали такой реализации оставлены как упражнение для читателя.


1 Термин контекст выполнения (execution context) используется в определении СОМ, чтобы описать все, что было впоследствии переименовано в апартамент (apartment). Апартамент – не поток и не процесс; однако он имеет общие для этих обоих понятии признаки. Подробно понятие апартамента описано в главе 5.


1 Точное произношение слова GUID является предметом горячих споров между разработчиками СОМ. Хотя спецификация СОМ формулирует, что GUID рифмуется с fluid (подвижный), а не squid (кальмар), автор уверен, что она ошибается, ссылаясь как на прецедент на слово languid (медлительный)


1 Который в значительной мере инспирирован дискуссией между автором и Tye McQueen во время семинара по СОМ.


1 Эти статьи можно найти на сайтах http:/www.develop.com/dbox/cxx/InterfacePtr.htm и http://www.develop.com/dbox/cxx/SmartPtr.htm.


1 Тип OLECHAR был предпочтен типу данных TCHAR, используемому Wn32 API, чтобы избежать необходимости поддержки двух версий каждого интерфейса (CHAR и WCHAR). Поддерживая только один тип символов, разработчики объектов становятся независимыми от типов символов препроцессора UNICODE, который используется их клиентами.


2 _UNCC является просто версией _U и имеет операторы приведения типа для wchart * и char *. Хотя расширенный вариант можно использовать где угодно, автор предпочитает использовать его только при согласовании с непостоянно корректными интерфейсами, чтобы подчеркнуть, что система типов в некоторой степени компрометируется. Увы, многие из СОМ API не являются постоянно корректными, так что промежуточный класс _UNCC применяется очень часто.


3 Хотя автор и находит строковые процедуры из ustring.h более чем подходящими для управления обработкой текстов в СОМ, библиотеки ATL и MFC используют несколько иной подход, основанный на аllоса и макросах. Более подробную информацию об этих подходах можно прочитать в соответствующей документации.


4 К нему можно обращаться и как к VARIANTARG. Термин VARIANTARG относится к вариантам, которые являются допустимыми типами параметров. Термин же VARIANT относится к вариантам, которые являются допустимыми результатами методов. Тип данных VARIANTARG является просто псевдонимом для VARIANT, и оба этих типа могут использоваться равнозначно.


1 Пакет Direct-to-COM фирмы Microsoft позволяет клиентам использовать свойства как открытые элементы данных интерфейса с помощью некоего очень хитрого механизма.


1 Спецификация СОМ использует термин логический поток (logical thread) для наименования последовательности вызовов методов, которая может превосходить физический OS-поток.


2 Объект, который обеспечивает выполнение GetErrorInfo, декларирует, что он явно программирует с использованием исключений СОМ и что никаких ошибочных исключений, сброшенных объектами младшего уровня, случайно не распространилось.


1 Хотя и мало смысла запрашивать «любую доступную реализацию» данного интерфейса, иногда имеет смысл произвести семантическое группирование реализаций, имеющих определенные общие черты высокого уровня, например, чтобы все они были животными или чтобы все они имели службу регистрации. Чтобы обеспечить обнаружение этого типа компонентов, СОМ поддерживает объявление такой систематики (taxonomy) посредством использования категорий компонентов (component categories). Поскольку часто это тот случай, когда все классы, принадлежащие к одной категории компонентов, будут реализовывать одно и то же множество интерфейсов, то такое условие, без сомнения, является достаточным для принадлежности к одной категории компонентов.


1 В Windows NT также имеется подсистема, известная как Service Control Manager, или просто Services, которая используется для запуска процессов, не зависящих от входа в систему. Далее в этой книге мы будем называть этот диспетчер управления сервисами NT SCM, чтобы отличать его от СОМ SCM.


2 Моникеры являются поисковыми объектами, которые скрывают детали активации или связывающего алгоритма. Более подробно моникеры обсуждаются далее в этой главе.



3 Степень изоляции, необходимая для вызова во внешнюю DLL, приблизительно эквивалентна вызову функции через вход таблицы vtbl.


1 Это разделение в значительной степени концептуально, так как библиотека СОМ и протокол передачи (wire-protocol) реализуют каждый примитив как отдельную ветвь программы и формат пакета.


2 Внутрипроцессные обработчики (in-process handlers) – в значительной степени пережитки документации OLE. Эти обработчики являются виутрипроцессными компонентами, выступающими в качестве представителей клиентской стороны объекта, который в действительности находится в другом процессе. Обработчики используются в документах OLE для кэширования изображений у клиента с целью сократить поток IPC (interprocess communication – межпроцессное взаимодействие) при перерисовке экрана. Хотя эти обработчики в общем случае производят считывание, они редко используются вне контекста документов OLE. Windows NT 5.0 будет обеспечивать дополнительные возможности для реализации обработчиков, но подробности того, как это будет достигнуто, были еще схематичны во время написания этой книги.


3 Требования параллелизма для класса должны технически соответствовать таким же требованиям в потоке вызова.


1 Эти аббревиатуры не допускаются в исходном коде или в конфигурационных файлах. Они просто дают возможность длинным именам ключей фигурировать в виде одной строки без разделителей в документации или других текстах о СОМ. Читателю следует раскрывать аббревиатуры при чтении вслух или при использовании в исходном коде.


2 Приведенный здесь способ записи использует стандартный синтаксис REGEDIT4 . Строки, содержащиеся внутри скобок, соответствуют именам ключей. Пары имя=значение (name = value) под ключом обозначают значения, присвоенные указанному ключу. Необычное имя "@" показывает значение ключа по умолчанию.


1 Формально CoCreateInstance возникла первой. CoCreateInstanceEx была добавлена в Windows NT 4.0, когда стало ясно, что некоторые разработчики хотели бы передавать информацию о безопасности и хосте API-функциям активации модели СОМ. В исходном прототипе для CoGetClassObject третий параметр был резервным, и NT 4.0 смог заимствовать этот резервный параметр для COSERVERINFO. К сожалению, в CoCreateInstance не было неиспользуемых параметров, поэтому была создана CoCreateInstanceEx . Можно поспорить, была бы ли также полезной версия CoGetClassObject, использующая MULTI_QI для связывания с более чем одним интерфейсом, но увы – на момент написания книги никакой CoGetClassObjectEx не существует. Тот же аргумент мог бы быть применен и по отношению к IMoniker::BindToObject и MULTI_QI.


1 Хотя использование MkParseDisplayName будет несколько менее эффективным, оно обладает гораздо большей гибкостью. Как отмечалось ранее, отображаемое имя может быть прочитано из файла или даже из пользовательского интерфейса. Отличным примером такого приложения является Internet Explorer фирмы Microsoft, так как он позволяет пользователям набирать произвольные имена объектов (URL), которые превращаются в моникеры (с использованием расширенной API-функции MkParseDisplayNameEx).


2 Контексты связывания используются композитными моникерами для оптимизации операций синтаксического анализа и связывания. Кроме того, контексты связывания позволяют клиентам выставить флаги CLSCTX, а также COSERVERINFO, хотя текущая реализация Class Moniker проигнорирует оба эти атрибута. Вместо этого Class Moniker предполагает, что он будет скомпонован с тем моникером, который ссылается на реализацию интерфейса IClassActivator, допускающим намного большую гибкость.


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.


1 Вероятно, в Windows NT 5.0 будет предусмотрена дополнительная поддержка для подтверждения того, что DLL освобождаются быстро и безошибочно. Подробности можно найти в документации SDK.


1 Отметим, что CLSID_Chimp и CLSID_Chimp2 являются сокращенной записью канонической формы фактических GUID, состоящих из 32 знаков.


1 Служебные данные счетчика ссылок можно сократить, если разработчик желает ограничить клиентское использование AddRef. Это очень опасная оптимизация, возникшая благодаря растущей популярности интеллектуальных указателей, и результатом ее часто является наличие избыточных (но безвредных) пар AddRef/Release.


1 Автор однажды уверовал, что раскраска (coloring) методов является наилучшим способом для обеспечения двух реализации IUnknown. Со временем способ, приведенный в данной книге, доказал свою большую пригодность и не меньшую эффективность.


1 Апартаменты являются более современным названием того, что в спецификации СОМ изначально именовалось контекстом исполнения (execution context).


1 Стоимость выполнения вызова метода из другого апартамента из-за непроизводительных издержек по переключению потоков может быть в тысячи раз выше, чем в случае, когда метод вызывается внутри апартамента.


1 Если импортирующий апартамент – тот, к которому принадлежит объект, то заместители не используются и импортированный указатель будут указывать прямо на объект.


2 Предпочтение UDP перед TCP (Transmission Control Protocol) – протоколом управления передачей – отдается из-за чрезмерных непроизводительных издержек при установке связи, обесчечиваемой TCP. СОМ, подобно DCE RPC, располагает информацию о своей безопасности и синхронизации протоколов ярусами в заголовках пакетов, используемых для передачи первого запроса RPC. Поскольку основанные на СОМ системы имеют тенденцию устанавливать и прерывать множество временных связей, то UDP является наилучшим выбором. При использовании передачи дейтаграмм, таких как UDP, динимическая библиотека RPC каждый раз выполняет коррекцию ошибок и алгоритмы контроля над потоком/перегрузкой.ТСР.


  • Страницы:
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33