Главная
 
Ghost Studio Вторник, 14.05.2024, 06:56:11



Приветствую Вас Гость | RSS
Главная
Меню сайта

Категории каталога
Разное [36]
Всякая всячина)))
Программирование графики [3]
Учебник по OpenGL [6]
Программирование под Windows [8]

Наш опрос
Какой мир вам больше нравится?
Всего ответов: 64

Главная » Статьи » Программирование под Windows

Инициализация TAPI
С чего начать?

В прошлой статье я кратко описал архитектуру Telephony API. Теперь пришло время детализации и немного практики.… Практиковаться будем на небольших экзамплах, которые будут постепенно увеличивать свои возможности.… На этом этапе возникает резонный вопрос: «С чего же начать разработку TAPI приложения?»

Начинать как всегда нужно с самого начала. Всё зависит от того, какое приложение вы пишете. Допустим это графическое оконное приложение, в которое вам необходимо добавить функции TAPI.... Писать приложение я начну на ассемблере (хатчевский пакет MASM32), во-первых, потому, что ассемблер - один из моих любимых языков (наряду с С++), во-вторых, хатчевский МАСМ32 обладает очень читабельным синтаксисом. Единственный минус – весьма и весьма паршивый инклюдный файл tapi32.inc из пакета. Этим вопросом я сейчас занимаюсь и, надеюсь, скоро на tgl.h12.ru появится новая, исправленная мною версия этого файла. Также приложение будет чистым Win32 приложением, т.е. используются только функции Win API. Незнакомым с этой темой, советую прочитать туториалы Iczelion’а на тему Win32 API (есть на wasm.ru). В качестве среды разработки я выбрал RadASM. Во-первых, на нём очень удобно разрабатывать большие приложения! Во-вторых, у него неплохой набор шаблонов, что тоже не может не радовать (лично меня бесит постоянно переписывать всякую чушь типа структуры WNDCLASSEX :) ). В-третьих, это просто дело вкуса.

От автора: разработка пользовательского интерфейса выходит за рамки этой серии статей, поэтому предполагается, что читатель имеет понятие о том, что такое «окно», «класс окна» и т.д. и т.п. не на уровне постылых компонентов, а на уровне Win32 API. Если же не знает, то я сказал, где можно просветиться по этому поводу. Я же буду говорить только о телефонии. Т.е., если мы, например, открываем линию (lineOpen), то вы сами будете решать, где и когда в приложении это делать (при нажатии на какую-либо кнопку, или при создании окна, или ещё где-то), это уже вопрос проектирования приложения.

Итак, канализация. Ой, извиняюсь… Инициализация. Первый шаг при разработке TAPI приложения. При инициализации происходят следующие фундаментальные события:

1) включается сервер TAPI (TAPISRV);
2) осуществляется подключение к этому серверу;
3) сервер производит все необходимые установки.

От автора: ещё раз напомню, что предметом изучения является TAPI 2.х (C/API), а не TAPI 3.х (COM/API). Поэтому, всё, сказанное ниже, не будет относиться к TAPI 3.х.

Для инициализации необходимо вызвать функцию lineInitializeEx. Вот её сигнатура (из MSDN):

LONG WINAPI lineInitializeEx(
LPHLINEAPP lphLineApp,
HINSTANCE hInstance,
LINECALLBACK lpfnCallback,
LPCSTR lpszFriendlyAppName,
LPDWORD lpdwNumDevs,
LPDWORD lpdwAPIVersion,
LPLINEINITIALIZEEXPARAMS lpLineInitializeExParams
);
Параметры

  • lphLineApp
    Указатель на область памяти, которая в случае успешного завершения функции получит хэндл TAPI.

  • hInstance
    Здесь должен помещаться хэндл приложения или библиотеки динамической компоновки (DLL).

  • lpfnCallback
    Указатель на определяемую разработчиком callback функцию, которая будет обрабатывать сообщения TAPI. Используется при установке такого метода обработки событий, как «скрытое окно» (“hidden window”). Мы будем использовать именно такой способ, поэтому ещё рассмотрим эту функцию более детально.

  • lpszFriendlyAppName
    Указатель на строку (заканчивающуюся нулем). Если значение этого параметра не равно NULL, оно должно содержать имя приложения. Если строка содержит NULL, по умолчанию используется имя файла модуля (его можно получить с помощью Win API функции GetModuleFileName).

  • lpdwNumDevs
    Указатель на память размером в двойное слово (DWORD). В случае успешного завершения функции в эту память записывается количество доступных приложению линий (line device).

  • lpdwAPIVersion
    Указатель на память размером DWORD, которая должна содержать версию (наивысшую), поддержку которой обеспечивает приложение. В нашем случае это версия 2.2, она будет записана как 00020002h (старшие полбайта содержат значение «до точки», а младшие, соответственно «после точки», так версия 1.3 выглядит как 00010003h).

  • lpLineInitializeExParams
    Указатель на структуру LINEINITIALIZEEXPARAMS, содержащую дополнительные параметры для связывания приложения и TAPI.

    Описанная выше функция синхронна, т.е. выполнение функции начинается тогда, когда она затребована, а завершение происходит при выходе из функции.

    От автора: возврат же из асинхронных функций производится немедленно, при этом выполнение самой операции продолжается в фоновом режиме. Выполнение основного потока программы продолжается. При завершении операции, система сообщает об этом вызвавшему потоку. С такими функциями мы будем встречаться очень часто.

    В использовании lineInitializeEx я думаю всё ясно. Кроме последнего параметра. Что это за структура LINEINITIALIZEEXPARAMS? Вот она:

    typedef struct lineinitializeexparams_tag {
    DWORD dwTotalSize;
    DWORD dwNeededSize;
    DWORD dwUsedSize;
    DWORD dwOptions;
    Union {
    HANDLE hEvent;
    HANDLE hCompletionPort;
    } Handles;
    DWORD dwCompletionKey;
    } LINEINITIALIZEEXPARAMS, FAR *LPLINEINITIALIZEEXPARAMS;
    Первые три параметра структуры определяют соответственно полный размер структуры в байтах, размер, необходимый для хранения всей возвращаемой информации, и размер той части структуры, которая содержит полезную информацию. Такой расклад будет во многих структурах, поэтому стоит запомнить значения параметров, ибо в дальнейшем я не буду объяснять их заново. На практике обычно имеет значение лишь значение первого поля.

    Дальше идет параметр dwOptions. Он является ключевым для этой структуры, ибо определяет тот самый механизм обработки событий (или уведомления о событиях, если быть точнее), о котором говорилось выше. Этот параметр может принимать следующие значения:

  • LINEINITIALIZEEXOPTION_CALLHUBTRACKING
    Этот механизм обработки используется только в TAPI 3.0 и выше.

  • LINEINITIALIZEEXOPTION_USECOMPLETIONPORT
    Устанавливается механизм обработки событий, называемый Комплексным (полным, завершенным, не знаю, как будет точнее…) портом (Completion Port). В этом случае TAPI посылает сообщение приложению, используя PostQueuedCompletionStatus, посылая тем самым сообщение в Completion Port. Порт этот можно создать при помощи функции CreateIoCompletionPort. Приложение получает событие через GetQueuedCompletionStatus.

  • LINEINITIALIZEEXOPTION_USEEVENT
    В случае использования Хэндла События, TAPI создает объект события на стороне приложения и возвращает его хэндл. Извлекается сообщение с помощью lineGetMessage.

  • LINEINITIALIZEEXOPTION_USEHIDDENWINDOW
    При использовании этого механизма TAPI создает скрытое окно, и в дальнейшем события посылаются процедуре этого окна. Эта процедура – callback-функция (lineCallbackProc). Этот механизм идентичен механизму, который используется для обработки сообщений обычных окон. Его я и использую в своём примере.

    Необходимость следующих параметров определяется выбранным механизмом обработки событий.

  • hEvent
    При обработке событий посредством Хэндла события в данное поле TAPI заносит собственно хэндл события :).

  • hCompletionPort
    При использовании Комплексного порта, в это поле нужно поместить его (порта) хэндл.

  • dwCompletionKey
    При том же использовании Комплексного порта, в это поле нужно поместить значение, возвращаемое GetQueuedCompletionStatus через параметр lpCompletionKey.

    Теперь, немного о callback функции lineCallbackProc...

    VOID FAR PASCAL lineCallbackFunc(
    DWORD hDevice,
    DWORD dwMsg,
    DWORD dwCallbackInstance,
    DWORD dwParam1,
    DWORD dwParam2,
    DWORD dwParam3
    );
    Параметры

  • hDevice
    Здесь должен лежать хэндл линии или звонка, связанного с callback функцией.

  • dwMsg
    Собственно сообщение.

  • dwCallbackInstance
    Это безобразие не интерпретируется TAPI.

    Потом идут параметры сообщения.

    Я думаю, что пришла пора немного размяться и написать ма-а-аленькую прогу. Пока она будет уметь только правильно проводить инициализацию. Назовем её TAPItest.

    ; TAPItest.inc

    include windows.inc ;подключение
    include user32.inc ;заголовочных
    include kernel32.inc ;файлов
    include shell32.inc
    include comctl32.inc
    include comdlg32.inc
    include tapi32.inc
    include masm32.inc
    includelib user32.lib ;подключение
    includelib kernel32.lib ;библиотек
    includelib shell32.lib
    includelib comctl32.lib
    includelib comdlg32.lib
    includelib tapi32.lib
    includelib masm32.lib

    WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD ;прототипы
    WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
    lineCallbackFunc PROTO :DWORD,
    :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
    .data
    AppName db 'TAPItest',0 ;имя программы
    dwHighVer dd 00020002h ;наивысшая поддерживаемая версия
    dwDeviceID dd 00000000h ;идентификатор девайса
    szDeviceClass db 'comm/datamodem',0 ;класс девайса
    .data?
    hInstance dd ? ;хэндл приложения
    CommandLine dd ? ;командная строка
    hWnd dd ? ;хэндл окна
    hLineApp HLINEAPP ? ;хэндл линии
    hLine HLINE ? ;хэндл TAPI
    dwNumDevs dd ? ;количество доступных девайсов

    ; TAPItest.asm

    .386
    .model flat,stdcall
    option casemap:none

    include TAPItest.inc

    .code
    start:
    invoke GetModuleHandle,NULL ;получаем хэндл приложения
    mov hInstance,eax
    invoke GetCommandLine ;
    здесь получаем хэндл командной строки
    mov CommandLine,eax
    invoke InitCommonControls
    invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
    invoke ExitProcess,eax

    WinMain proc \ hInst:HINSTANCE,hPrevInst:
    HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    ;---стандартная «начинка» WinMain---
    WinMain endp

    WndProc proc hWin:HWND,
    uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    LOCAL LineInitExParam:LINEINITIALIZEEXPARAMS
    mov LineInitExParam.dwTotalSize,
    SIZEOF LINEINITIALIZEEXPARAMS
    mov lineInitExParam.dwOptions, \
    LINEINITIALIZEEXOPTION_USEHIDDENWINDOW
    ;---здесь обработчики разных событий---
    ;---Бла-бла-бла------------------------
    ;---потом где-то в коде----------------
    invoke lineInitializeEx,addr hLineApp,
    hInstance,addr lineCallbackFunc,addr AppName,\
    addr dwNumDevs,addr dwHighVer,addr LineInitExParam
    .if eax==0
    ;---здесь то, о чем мы ещё поговорим---
    .endif
    WndProc endp

    lineCallbackFunc proc hDevice:DWORD,dwMsg:DWORD,
    dwCallbackInstance:DWORD,
    dwParam1:DWORD,dwParam2:DWORD,dwParam3:DWORD
    .if dwMsg==LINE_CREATE
    ;---перехват сообщения (LINE_CREATE)---
    .endif
    ret
    lineCallbackFunc endp

    end start
    Да, и ещё... В случае успеха, lineInitializeEx, как почти все TAPI функции возвращает 0, в случае провала – одно из отрицательных константных значений LINEERR_constant. Некоторые строки прокомментированы прямо в листинге, а некоторые я сейчас поясню. Я, конечно, не стал полностью описывать содержание функций WinMain и WinProc, ИМХО глупо постоянно повторять одно и то же в разных туториалах.… В WinProc инициализируем TAPI. Вызов lineInitializeEx однозначен и, думаю, не вызывает вопросов.

    Сообщения TAPI пока перехватывать не будем, поэтому пока я только показал пример использования callback-функции lineCallbackFunc.

    Вот мы и инициализировали Telephony API! По-моему выговорить десять раз подряд слово «инициализация» и то сложнее, чем инициализировать TAPI.

    Первый шаг сделан. Скоро пойдём дальше...
  • Категория: Программирование под Windows | Добавил: Buba (22.06.2007) | Автор: Fess (TGL team)
    Просмотров: 3130 | Комментарии: 3 | Рейтинг: 0.0/0 |

    Всего комментариев: 0
    Имя *:
    Email *:
    Код *:
    Форма входа

    Поиск

    Друзья сайта

    Статистика


    Copyright MyCorp © 2024