Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

80

GUID

ВСША всем обычным летательным аппаратам FAA присваивает N-номер (N number), который идентифицирует самолет, — как номерной знак идентифицирует Вашу машину. Этот номер уникален для каждого самолета и используется пилотом в переговорах с авиадиспетчерами. В этом разделе мы обсудим GUID, которые являются такими «опознавательными знаками» компонентов и интерфейсов.

Вгл. 3 я предложил Вам представлять себе IID как константу, идентифицирующую данный интерфейс. Однако, как Вы могли видеть из определения IID_IX, IID — это константа особого рода:

extern const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

На самом деле IID представляет собой тип, определенный как структура длинной 128 битов (16 байтов) под названием GUID. GUID — аббревиатура Globally Unique IDentifier (глобально уникальный идентификатор;

произносится как «гуид» — как первая часть в слове geoduck1 и последняя — в druid).

Зачем нужен GUID?

Почему мы используем GUID, а не длинное целое (long integer)? С помощью длинных целых можно однозначно задать 232 интерфейсов. Я сильно сомневаюсь, что большее их число когда либо понадобится. Однако настоящая проблема не в том, сколь много интерфейсов мы сможем однозначно задать, но в том, как гарантировать уникальность идентификатора интерфейса. Если два идентификатора совпадают, клиент легко может получить от QueryInterface неверный указатель на интерфейс. Проблема усложняется тем, что компоненты создаются разработчиками по всему земному шару. Если Сара в Ако и Линн в Таксоне разрабатывают новые интерфейсы СОМ, то как им удостовериться, что идентификаторы интерфейсов не будут конфликтовать? Можно было бы договориться о чем-нибудь вроде N-номеров летательных аппаратов и учредить некое центральное агентство, наподобие FAA, для выделения идентификаторов. Централизованная организация подходит для относительно ограниченного числа летательных аппаратов; но я сомневаюсь, что какое-нибудь агентство смогло бы столь же успешно, как FAA, работать с тем количеством интерфейсов, которое необходимо для средней программы.

Для GUID есть более удачное решение. Уникальный GUID можно сгенерировать программно, без какой-либо координирующей организации. Microsoft Visual C++ предоставляет для генерации GUID две программы — утилиту командной строки UUIDGEN.EXE и диалоговую программу на VC++, GUIDGEN.EXE. Если я сейчас запущу UUIDGEN.EXE, то получу строку, представляющую некоторый GUID:

{166769E1-88E8-11CF-A6BB-0080C7B2D692}

При всяком новом запуске UUIDGEN получается иной GUID. Если Вы запустите UUIDGEN на своей машине, то получите GUID, отличный от моего. Если миллионы (я надеюсь) людей, читающих эту книгу, сейчас запустят UUIDGEN, они получат миллион разных GUID.

Исходный текст GUIDGEN.EXE можно найти в примерах программ Microsoft Visual C++. Но я и так могу сказать Вам, как работает эта программа: она просто вызывает функцию библиотеки СОМ Microsoft CoCreateGuid, которая вызывает функцию RPC UuidCreate.

Теория GUID

GUID по определению уникален «в пространстве и во времени». Для обеспечения «географической» уникальности каждый GUID использует 48-битовое значение, уникальное для компьютера, на котором он генерируется. Обычно в качестве такого значения берется адрес сетевой платы. Такой подход гарантирует, что любой GUID, полученный на моем компьютере, будет отличаться от любого, сгенерированного на Вашем компьютере. Для тех компьютеров, в которых не установлен сетевой адаптер, используется другой алгоритм генерации уникальных значений. В каждом GUID 60 битов отведено для указания времени. Туда заносится число 100-наносекундных интервалов, прошедших с 00:00:00:00 15 октября 1582 года. Используемый в настоящее время алгоритм генерации GUID начнет выдавать повторяющиеся значения примерно в 3400 году. (Я подозреваю, что очень немногие из нынешних программ, за исключением некоторых на Фортране, еще будут использоваться в 3400 году; но я верю, что к этому времени уже выйдет Windows 2000.)

GUID придумали толковые ребята из Open Software Foundation (OSF); правда, они использовали термин UUID (Universally Unique IDentifiers — вселенски уникальные идентификаторы). UUID разработали для использования в среде распределенных вычислений (DCE, Distributed Computing Environment). Вызовы удаленных процедур (RPC) DCE используют UUID для идентификации вызываемого, т.е. практически затем же, зачем и мы.

1 Нормальные люди произносят это как «gooey duck». Программисты же говорят «GUI duck».

81

Дополнительно о генерации UUID или GUID можно прочитать в CAE Specification X/Open DCE: Remote Procedure Call.

Объявление и определение GUID

Поскольку размер GUID велик (128 битов), не хотелось бы, чтобы они повторялись в нашем коде повсюду. В гл. 5 GUID определялись в файле GUIDS.CPP примерно так:

extern const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

Объявлены они были в файле IFACE.H так:

extern “C” const IID IID_IX;

Ввести для GUID два файла, один с определениями, а другой с объявлениями — изрядная морока. Чтобы определить и объявить GUID одним оператором, используйте макрос DEFINE_GUID, который определен в OBJBASE.H. Для использования DEFINE_GUID генерируйте GUID с помощью GUIDGEN.EXE. Эта программа генерирует GUID в различных форматах — выберите второй из них. Этот формат используется в следующем примере.

// {32bb8320-b41b-11cf-a6bb-0080c7b2d682} DEFINE_GUID(<<name>>,

{0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

Вставьте сгенерированный GUID в заголовочный файл. Замените <<name>> идентификатором, используемым в Вашем коде, — например, IID_IX:

// {32bb8320-b41b-11cf-a6bb-0080c7b2d682} DEFINE_GUID(IID_IX,

{0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

В соответствии с определением в OBJBASE, DEFINE_GUID генерирует что-то вроде:

extern “C” const GUID IID_IX;

Однако, если после OBJBASE.H включить заголовочный файл INITGUID.H, макрос DEFINE_GUID будет раскрываться так:

extern “C” const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,

{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}};

Механизм работы этих заголовочных файлов представлен на рис. 6-2. Заголовок IFACE.H использует макрос DEFINE_GUID для объявления IID_IX. Идентификатор IID_IX определен в файле GUIDS.H. Он определен там потому, что заголовочный файл INITGUID.H включен после OBJBASE.H и перед IFACE.H. С другой стороны, в файле CMPNT.CPP IID_IX объявлен но не определен, поскольку заголовочный файл INITGUID.H здесь не включен.

Так как я старался сделать примеры в книге максимально ясными, то DEFINE_GUID я в них не использовал, но явно определял используемые GUID.

GUIDS.CPP

 

 

#include <objbase.h>

 

IID_IX определяется,

#include

<initguid.h>

 

 

так как INITGUID.H

 

 

#include

"Iface.h"

 

включен

IFACE.H

DEFINE_GUID(IID_IX, 0x32bb8320, 0xb41b, 0x11cf,

0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82);

CMPNT.CPP

 

 

#include

<objbase.h>

 

IID_IX объявляется,

#include

"Iface.h"

 

 

так как INITGUID.H

 

 

(здесь идет код)

 

не включен

 

 

 

 

 

Рис. 6-2 Включение INITGUID.H заставляет макрос DEFINE_GUID определить GUID

Соседние файлы в предмете Программирование на C++