Программирование - на главную
    Главная   |    Рассылки   |    Форум программистов

  Программирование в Интернет
PHP
ASP .NET
Perl
SSI
JavaScript
CSS
HTML
Разное
  Программирование под Windows
Pascal, Delphi
C++, Builder
BIOS
Алгоритмы
Разное
  Программирование графики
DirectX
OpenGL
Графика
  Разное
Форум программистов
Партнерские программы
Создать интернет-магазин
Рассылки
Написать
  Навигация: Главная > Программирование под Windows > Различная документация по программированию > Инициализация TAPI  

Инициализация 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.

    Первый шаг сделан. Скоро пойдём дальше...

    © Fess (TGL team) - http://www.ru-coding.com/
    Условия использования материалов сайта.
  •   Счетчики и ссылки

    Rambler's Top100


      На правах рекламы
    Copyright © 2005-2012 Ru-Coding.com - все о программировании.