netlib.narod.ru< Назад | Оглавление | Далее >

Использование адресов

Как вы уже читали, в сети для доставки данных используется IP-адрес и номер порта. В DirectPlay вы конструируете этот адрес в его собственном объекте IDirectPlay8Address. Объект адреса предоставляет для использования ряд функций, но в этой книге мы будем работать только с тремя из них (они перечислены в таблице 5.3).


Таблица 5.3. Функции IDirectPlay8Address



Функция Описание

IDirectPlay8Address::Clear Очищает все данные адреса.
IDirectPlay8Address::SetSP Устанавливает поставщика услуг.
IDirectPlay8Address::AddComponent Добавляет компоненты адреса.


Инициализация объекта адреса

Перед тем, как вы сможете использовать объект адреса, необходимо создать его с помощью показанной ранее функции CoCreateInstance:

IDirectPlay8Address *pDPAddress;

if(FAILED(CoCreateInstance(CLSID_DirectPlay8Address,
                           NULL, CLSCTX_INPROC,
                           IID_IDirectPlay8Address,
                           (void**)&pDPAddress))) {
    // Произошла ошибка
}

Добавление компонентов

Объект адреса просто содержит строку в формате Unicode. Эта строка содержит название поставщика услуг, номер порта, и другую информацию. Его единственное назначение — построить эту строку, которую будут использовать другие объекты.

Чтобы добавить компонент к объекту адреса используйте функцию IDirectPlay8Address::AddComponent:

HRESULT IDirectPlay8Address::AddComponent(
     const WCHAR *const pwszName, // Имя устанавливаемого компонента
     const void  *const lpvData,  // Буфер, содержащий устанавливаемую
                                  // информацию о компоненте
     const DWORD dwDataSize,      // Размер используемого буфера данных.
     const DWORD dwDataType);     // Тип используемых данных.

Эта небольшая функция требует большого количества пояснений, так что давайте приостановимся. Первый аргумент, pwszName, — это указатель на строку Unicode, содержащую имя добавляемого компонента. В DirectPlay есть макросы для каждого из этих компонентов, которые перечислены в таблице 5.4.


Таблица 5.4. Макросы для имен компонентов



Компонент Макрос

Поставщик DPNA_KEY_PROVIDER
Сетевое устройство DPNA_KEY_DEVICE
Номер порта DPNA_KEY_PORT
Имя/адрес узла DPNA_KEY_HOSTNAME
Номер телефона DPNA_KEY_PHONENUMBER
Скорость передачи DPNA_KEY_BAUD
Контроль потока DPNA_KEY_FLOWCONTROL
Четность DPNA_KEY_PARITY
Стоп-биты PNA_KEY_STOPBITS


Какой буфер передавать функции AddComponent через аргумент lpvData зависит от типа передаваемого компонента, но обычно это строка (Unicode или ANSI), двойное слово (DWORD), GUID или двоичные данные. Тип передаваемых данных сообщает параметр dwDataType, в котором можно использовать один из макросов, перечисленных в таблице 5.5.


Таблица 5.5. Типы данных компонентов



Тип Макрос

Строка (Unicode) DPNA_DATATYPE_STRING
Строка (ANSI) DPNA_DATATYPE_STRING_ANSI
DWORD DPNA_DATATYPE_DWORD
GUID DPNA_DATATYPE_GUID
Двоичные данные DPNA_DATATYPE_BINARY


Последний аргумент, dwDataSize, определяет размер отправляемых данных (DWORD, длину строки, размер GUID и т.д.). Достаточно трудно представить использование этого метода для установки данных, но вам должны помочь примеры, которые я приведу в разделе «Выбор порта» далее в этой главе. Сейчас взгляните на рис. 5.7, где показаны компоненты, которые вы добавляете к объекту адреса, и тип данных каждого компонента.


Рис. 5.7. Объект адреса содержит информацию из различных компонентов

Рис. 5.7. Объект адреса содержит информацию из различных компонентов. Каждому компоненту соответствует его тип данных


Установка поставщика услуг

После того, как вы создали объект адреса, и поняли концепцию компонентов, следует выбрать тип поставщика услуг. Это единственный параметр, для установки которого не используется функция AddComponent. Вместо нее применяется функция IDirectPlay8Address::SetSP:

HRESULT IDirectPlay8Address::SetSP(
     const GUID *const pguidSP); // GUID поставщика услуг

GUID каждого поставщика услуг приведен в таблице 5.6. Выбор зависит от вас, но в этой книге я использую только поставщика услуг TCP/IP (CLSID_DP8SP_TCPIP).


Таблица 5.6. Поставщики услуг DirectPlay



Тип GUID

TCP/IP CLSID_DP8SP_TCPIP
IPX CLSID_DP8SP_IPX
Модем CLSID_DP8SP_MODEM
Последовательный порт CLSID_DP8SP_SERIAL


С учетом вышесказанного, для установки используемого поставщика услуг можно использовать следующий код:

// Установка поставщика услуг TCP/IP
if(FAILED(pDPAddress->SetSP(&CLSID_DP8SP_TCPIP))) {
     // Произошла ошибка
}

Выбор порта

Далее на очереди выбор порта, либо для открытия сессии (на сервере или в одноранговой сети), либо для подключения к удаленному компьютеру в сетевой модели клиента. Если вы подключаетесь к удаленной системе, то должны знать какой порт использует приложение, чтобы суметь установить соединение и отправить данные.

ПРИМЕЧАНИЕ
Номер используемого порта можно выбирать, но не стоит использовать зарезервированные значения (от 1 до 1024). Для безопасности выберите какой-нибудь номер больше 1024.
Вы можете делегировать выбор порта DirectPlay, указав в номере порта 0, но тогда номер порта может быть любым и вам придется запрашивать его. Предпочтительнее самому выбирать порт.

Вы устанавливаете порт, используя функцию IDirectPlay8Address::AddComponent. Хотя, как я уже говорил, эта функция может вызвать замешательство, вы вскоре увидите, как просто с ней работать.

Вот вызов, используемый для установки порта с помощью функции AddComponent:

// dwPort это значение типа DWORD представляющее
//        номер используемого порта
if(FAILED(pDPAddress->AddComponent(DPNA_KEY_PORT, &dwPort,
                       sizeof(DWORD), DPNA_DATATYPE_DWORD))) {
    // Произошла ошибка
}

Как видите, добавить компонент совсем не трудно, поскольку DirectPlay максимально облегчает задачу! На данный момент мы практически закончили инициализацию адреса. Что же осталось?

Назначение устройства

Хотя вы и выбрали поставщика услуг, в вашей системе его могут использовать несколько устройств. Это происходит, например, в том случае, когда вы подключены к Интернету через сетевую карту и через модем — оба используют TCP/IP. В таких случаях вы должны перечислить устройства и выбрать необходимое.

СОВЕТ
Если у вас только один адаптер, можете пропустить этот шаг, поскольку DirectPlay будет использовать первое найденное устройство.

На рис. 5.8 показан массив поставщиков услуг. Перечисление выбирает всех годных к использованию поставщиков услуг и предоставляет вам информацию о них в удобном для работы виде. Перечисление в DirectPlay слегка отличается от общепринятого в Windows метода перечисления; здесь не применяется функция обратного вызова, к которой обращаются каждый раз, когда найден экземпляр требуемого объекта. Вместо этого вы получаете буфер, содержащий данные всех поставщиков услуг в виде массива структур.


Рис. 5.8. Перечисление создает список поставщиков услуг системы и помещает его в легкодоступный массив поставщиков

Рис. 5.8. Перечисление создает список поставщиков услуг системы и помещает его в легкодоступный массив поставщиков


Выполняется перечисление с помощью следующей функции (она также применима для сетевых объектов клиента и одноранговой сети):

HRESULT IDirectPlay8Server::EnumServiceProviders(
     const GUID *const pguidServiceProvider, // GUID поставщика услуг
     const GUID *const pguidApplication,     // NULL
     const DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer,
     DWORD *const pcbEnumData,               // Указатель на DWORD содержащий
                                             // размер буфера данных
     DWORD *const pcReturned,                // Указатель на DWORD содержащий
                                             // количество перечисленных элементов
                                             // в буфере
     const DWORD dwFlags);                   // 0

Этой функции в первом параметре вы передаете GUID поставщика услуг (или NULL, если нужны все поставщики услуг). Параметр pSPInfoBuffer — это указатель на массив структур DPN_SERVICE_PROVIDER_INFO, которые данная функция заполняет информацией, полученной при перечислении. Объявление этой структуры выглядит так:

typedef struct _DPN_SERVICE_PROVIDER {
     DWORD dwFlags;    // 0
     GUID  guid;       // Guid устройства
     WCHAR *pwszName;  // Имя устройства
     PVOID pvReserved; // 0
     DWORD dwReserved; // 0
} DPN_SERVICE_PROVIDER;

Вызывая функцию вы предоставляете ей переменную типа DWORD (в параметре pcdEnumData), в которую записывается общий размер возвращаемых данных. Она нужна по единственной причине — выполнить предварительное перечисление, чтобы узнать требуемый размер буфера, и затем выделить достаточное количество памяти для хранения результатов перечисления.

Вот пример перечисления поставщиков услуг TCP/IP. Этот пример формирует список устройств, имеющих доступ к указанному поставщику услуг, и из этого списка вы можете выбрать устройство, которое будет использоваться в объекте адреса.

DPN_SERVICE_PROVIDER_INFO *pSP = NULL;
DPN_SERVICE_PROVIDER_INFO *pSPPtr;

DWORD dwSize = 0;
DWORD dwNumSP = 0;
DWORD i;

// Запрашиваем необходимый размер буфера данных
hr = pDPServer->EnumServiceProviders(&CLSID_DP8SP_TCPIP,
                           NULL, pSP, &dwSize, &dwNumSP, 0);

// Возвращаем код ошибки, если буфер мал,
// а все остальное нормально
if(hr != DPNERR_BUFFERTOOSMALL) {
    // Произошла непредусмотренная ошибка
} else {
    // Выделяем память под буфер и повторяем перечисление
    pSP = (DPN_SERVICE_PROVIDER_INFO*)new BYTE[dwSize];
    if(SUCCEEDED(pDPServer->EnumServiceProviders(
                           &CLSID_DP8SP_TCPIP, NULL, pSP,
                           &dwSize, &dwNumSP, 0))) {
        // Перечисление завершено, перебираем элементы
        pSPPtr = pSP;
        for(i = 0; i < dwNumSP; i++) {
            // pSPPtr->pwszName содержит строку Unicode
            // с именем поставщика
            // pSPPtr->guid содержит GUID поставщика услуг
            pSPPtr++; // Переходим к следующему
                      // поставщику услуг в буфере
        }
    }
    // Освобождаем занятую буфером память
    delete[] pSP;
}

 

СОВЕТ
Если вы хотите перечислить всех поставщиков услуг, а не только TCP/IP, замените CLSID_DP8SP_TCPIP на NULL.

Скорее всего, вы будете показывать названия поставщиков услуг пользователю, чтобы он выбрал того, который будет использовать. В комплекте DirectX SDK поставляется демонстрационная программа AddressOverride, показывающая как это делается.

Получив GUID поставщика услуг вы используете его для завершения формирования адреса. Это снова делается путем вызова функции IDirectPlay8Address::AddComponent, которой на этот раз передается GUID:

// guidSP = GUID поставщика услуг
if(FAILED(pDPAddress->AddComponent(DPNA_KEY_PROVIDER,
               &guidSP, sizeof(GUID), DPNA_DATATYPE_GUID))) {
    // Произошла ошибка
}

Теперь вы заполнили все компоненты адреса и можете использовать его.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz