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. Объект адреса содержит информацию из различных компонентов. Каждому компоненту соответствует его тип данных
После того, как вы создали объект адреса, и поняли концепцию компонентов, следует выбрать тип поставщика услуг. Это единственный параметр, для установки которого не используется функция 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))) { // Произошла ошибка }
Далее на очереди выбор порта, либо для открытия сессии (на сервере или в одноранговой сети), либо для подключения к удаленному компьютеру в сетевой модели клиента. Если вы подключаетесь к удаленной системе, то должны знать какой порт использует приложение, чтобы суметь установить соединение и отправить данные.
Вы устанавливаете порт, используя функцию IDirectPlay8Address::AddComponent. Хотя, как я уже говорил, эта функция может вызвать замешательство, вы вскоре увидите, как просто с ней работать.
Вот вызов, используемый для установки порта с помощью функции AddComponent:
// dwPort это значение типа DWORD представляющее // номер используемого порта if(FAILED(pDPAddress->AddComponent(DPNA_KEY_PORT, &dwPort, sizeof(DWORD), DPNA_DATATYPE_DWORD))) { // Произошла ошибка }
Как видите, добавить компонент совсем не трудно, поскольку DirectPlay максимально облегчает задачу! На данный момент мы практически закончили инициализацию адреса. Что же осталось?
Хотя вы и выбрали поставщика услуг, в вашей системе его могут использовать несколько устройств. Это происходит, например, в том случае, когда вы подключены к Интернету через сетевую карту и через модем — оба используют TCP/IP. В таких случаях вы должны перечислить устройства и выбрать необходимое.
На рис. 5.8 показан массив поставщиков услуг. Перечисление выбирает всех годных к использованию поставщиков услуг и предоставляет вам информацию о них в удобном для работы виде. Перечисление в DirectPlay слегка отличается от общепринятого в Windows метода перечисления; здесь не применяется функция обратного вызова, к которой обращаются каждый раз, когда найден экземпляр требуемого объекта. Вместо этого вы получаете буфер, содержащий данные всех поставщиков услуг в виде массива структур.
Рис. 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; }
Скорее всего, вы будете показывать названия поставщиков услуг пользователю, чтобы он выбрал того, который будет использовать. В комплекте 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 | < Назад | Оглавление | Далее > |