用TAPI為掌上電腦開發(fā)通訊應用程序
發(fā)表時間:2023-08-13 來源:明輝站整理相關軟件相關文章人氣:
[摘要]中國地質(zhì)大學(北京)計算機系 田東風掌上電腦(即PPC,Palmsize PC)以Windows CE為操作系統(tǒng) 。Windows CE是一種模塊化的、開放的、實時的、具有強大通信能力的、搶先式、多...
中國地質(zhì)大學(北京)計算機系 田東風
掌上電腦(即PPC,Palmsize PC)以Windows CE為操作系統(tǒng) 。Windows CE是一種模塊化的、開放的、實時的、具有強大通信能力的、搶先式、多任務的嵌入式操作系統(tǒng)。它具備高性能、高效率的OS特性,包括按需換頁、共享存儲、交叉處理同步、支持大容量堆(heap)等。它支持文件系統(tǒng)、注冊表、以及對象存儲(ObjectStore)技術。通過UNICODE完全支持國際字符集。它具有靈活的電源管理,包括睡眠/喚醒模式。它有支持特定目標應用的豐富服務,例如手寫體、流式Video等等。
由于掌上電腦有Windows圖形用戶界面,因此操作簡單方便。更由于掌上電腦只有手掌大小, 因此特別適用于移動計算和移動通訊領域。Windows CE提供了豐富的通信支持:撥號連接、LAN,提供與PC、內(nèi)聯(lián)網(wǎng)、以及Internet的連接。提供基本的通信基礎結構,包括:套接字(socket)、Internet的TCP/IP、PPP、IrDA、遠程訪問、TAPI(Telephoney API)以及Unimodem、WinInet、Win32串行、SLIP驅(qū)動程序,以及PC連接性的支持。并支持廣泛的通信硬件。
下面以兩個掌上電腦之間通過MODEM進行遠程通訊為例,說明掌上電腦上的通訊程序設計的主要過程。兩個掌上電腦之間通過MODEM進行遠程通訊程序設計時主要有兩種方法。一種方法是直接利用串行通訊函數(shù)而不用TAPI,另一種方法是利用TAPI及串行通訊函數(shù)。由于利用TAPI可以簡化使用MODEM的過程,并且TAPI已經(jīng)成為事實上的工業(yè)標準,因此,本文介紹采用TAPI的方法。
TAPI函數(shù)以lineXXXXX...的形式命名,其主要函數(shù)的具體功能介紹如下。
1. LONG lineGetID(HLINE hLine, DWORD dwAddressID, HCALL hCall, DWORD dwSelect, LPVARSTRING lpDeviceID, LPCTSTR lpszDeviceClass):獲取或指定開放線路,地址或呼叫相關聯(lián)的設備標識符。它返回一個MODEM句柄。。在進行呼叫之前,程序常需要MODEM句柄來檢索MODEM的配置和性能,程序可以通過調(diào)用GetCommProperties()以讀取COMMPROP和COMMCONFIG結構來了解MODEM的信息,而GetCommProperties()就需要lineGetID()返回的MODEM句柄。
2. LONG lineInitialize(LPHLINEAPP lphLineApp, HINSTANCE hInstance, LINECALLBACK lpfnCallback, LPCTSTR lpszAppName, LPDWORD lpdwNumDevs):初始化TAPI線路。在用TAPI通過MODEM進行遠程通訊程序設計時,必不可少的是調(diào)用lineInitialize()函數(shù)以初始化TAPI。lineInitialize()分配為支持邏輯線路設備的使用而必須的內(nèi)部資源。它還登記了一個回調(diào)函數(shù),使操作系統(tǒng)通過該函數(shù)將有關線路狀態(tài)的消息返回給程序。
3.lineShutDown(hTAPI):關閉TAPI。它是與lineInitialize()相對應的函數(shù),當程序使用完線路設備后,應調(diào)用lineShutDown(hTAPI)以釋放為線路設備分配的資源。
4.lineNegotiateAPIVersion(hAPI,dwDeviceID,dwLowVersion,dwHighVersion,&dwVersionToUse,&extensions):協(xié)商TAPI版本號。TAPI是需要版本協(xié)商的一種Win32 API。版本協(xié)商確保當安裝了新版本的TAPI驅(qū)動程序時,程序仍能安全正常運行。
5.lineGetDevCaps(hAPI,dwLine,dwVersionToUse,dwExtVersion,&linedevcaps):返回指定邏輯線路設備的能力。
6.LONG lineGetDevConfig (DWORD dwDeviceID, LPVARSTRING lpDeviceConfig, LPCTSTR lpszDeviceClass):返回指定邏輯線路設備的缺省配置。
7.LONG lineSetDevConfig (DWORD dwDeviceID, LPVOID const lpDeviceConfig, DWORD dwSize, LPCTSTR lpszDeviceClass):設置指定媒體流設備。
8.LONG lineConfigDialogEdit (DWORD dwDeviceID, HWND hwndOwner, LPCTSTR lpszDeviceClass, LPVOID const lpDeviceConfigIn, DWORD dwSize, LPVARSTRING lpDeviceConfigOut):顯示一個允許用戶改變邏輯線路設備的配置數(shù)據(jù)的對話框。
9.LONG lineOpen(HLINEAPP hLineApp, DWORD dwDeviceID, LPHLINE lphLine, DWORD dwAPIVersion, DWORD dwExtVersion, DWORD dwCallbackInstance, DWORD dwPrivileges, DWORD dwMediaModes, LPLINECALLPARAMS const lpCallParams):打開指定邏輯線路設備,并提供后續(xù)監(jiān)視和控制線路的功能。調(diào)用lineInitialize()函數(shù)初始化TAPI后,就可以調(diào)用lineOpen()函數(shù)以打開線路。
10.LONG lineClose(HLINE hLine):關閉指定邏輯線路設備。
11.LONG lineMakeCall(HLINE hLine, LPHCALL lphCall, LPCTSTR lpszDestAddress, DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams): 初始化輸出撥號,進行呼叫,并返回線路句柄以進行數(shù)據(jù)傳輸。
12.LONG lineDrop(HCALL hCall, LPCTSTR lpsUserUserInfo, DWORD dwSize):收線或斷開呼叫。當程序結束呼叫時,需要調(diào)用lineDrop()函數(shù)以斷開或中止呼叫。
13.LONG lineDeallocateCall(HCALL hCall):釋放系統(tǒng)為呼叫分配的內(nèi)存。當程序結束呼叫時,除了需要調(diào)用lineDrop()函數(shù)以斷開或中止呼叫外,還調(diào)用lineDeallocateCall()函數(shù)以釋放系統(tǒng)為呼叫分配的內(nèi)存,調(diào)用lineClose()函數(shù)以關閉線路,調(diào)用lineShutdown()函數(shù)以將程序與TAPI斷開。
總之,在通過MODEM進行遠程通訊程序設計時,必不可少的是要調(diào)用lineInitialize()函數(shù)以初始化TAPI,以及調(diào)用lineOpen()函數(shù)以打開線路,調(diào)用lineMakeCall()函數(shù)以進行撥號。當程序撥號成功后,就可以使用由lineMakeCall()函數(shù)返回的線路句柄進行數(shù)據(jù)傳輸了!除此之外,為了編寫可靠的遠程通訊程序,還應調(diào)用有關檢測線路設備能力的函數(shù),檢測TAPI版本兼容性的函數(shù),檢測線路當前使用狀態(tài)的函數(shù)等以適應各種情況。當程序結束呼叫時,需要調(diào)用lineDrop()函數(shù)以斷開和中止呼叫,調(diào)用lineDeallocateCall()函數(shù)以釋放系統(tǒng)為呼叫分配的內(nèi)存,調(diào)用lineClose()函數(shù)以關閉線路,調(diào)用lineShutdown()函數(shù)以將程序與TAPI斷開。
下面結合主要代碼說明以上描述的過程。
#include <tapi.h> //TAPI.DLL 頭文件
#define TAPI_VERSION_2_0 0x00020000
#define TAPI_CURRENT_VERSION TAPI_VERSION_2_0
typedef struct tagLINEINFO
{
HLINE hLine;// 由lineOpen()返回的線路句柄
BOOL bVoiceLine;
DWORD dwAPIVersion,dwNumOfAddress,dwPermanentLineID;
TCHAR szLineName[256];
} LINEINFO, *LPLINEINFO;
......
BOOL CALLBACK MainWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
...
// 初始化TAPI
if (InitializeTAPI ())
{
if (g_hLineApp)
lineShutdown (g_hLineApp);//關閉TAPI!
DestroyWindow (hwnd);
}
return TRUE;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_DIAL:
{
......
// 撥號!
MakePhoneCall (g_szCurrentNum); return TRUE;
}
}
break;
}
default:
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
return FALSE;
}
//初始化TAPI函數(shù):
DWORD InitializeTAPI ()
{
DWORD dwLineID, dwReturn, dwTimeCount = GetTickCount ();
//初始化TAPI
while ( (dwReturn = lineInitialize (&g_hLineApp, g_hInst, (LINECALLBACK) lineCallbackFunc, g_szAppName,
&g_dwNumDevs)) == LINEERR_REINIT)
{
if (GetTickCount () > 5000 + dwTimeCount)
{
if (MessageBox (g_hwndMain, TEXT("不能初始化..."),
EXT("警告"), MB_OKCANCEL) == IDOK)
break;
dwTimeCount = GetTickCount ();
}
}
if (dwReturn)
return dwReturn;
if (g_dwNumDevs == 0)
{
return LINEERR_NODEVICE;
}
if (! (g_lpLineInfo = (LPLINEINFO) LocalAlloc (
LPTR,
sizeof (LINEINFO) * g_dwNumDevs)))
{
return LINEERR_NOMEM;
}
for (dwLineID = 0; dwLineID < g_dwNumDevs; ++dwLineID)
{//獲取線路信息
GetLineInfo (dwLineID, &g_lpLineInfo [dwLineID]);
}
return ERR_NONE;
}
//撥號函數(shù)!
VOID MakePhoneCall (LPCTSTR lpszPhoneNum)
{
DWORD dwReturn,
dwSizeOfTransOut = sizeof (LINETRANSLATEOUTPUT),
dwSizeOfCallParams = sizeof (LINECALLPARAMS);
LPLINECALLPARAMS lpCallParams = NULL;
LPLINETRANSLATEOUTPUT lpTransOutput = NULL;
TCHAR szDialablePhoneNum[TAPIMAXDESTADDRESSSIZE + 1] = {'\0'};
g_MakeCallRequestID = 0;
//打開線路
if (dwReturn = lineOpen (g_hLineApp,
g_dwCurrentLineID,
&g_CurrentLineInfo.hLine, g_CurrentLineInfo.dwAPIVersion, 0, 0, LINECALLPRIVILEGE_NONE,
0, NULL))
{
goto exit;
}
......
//撥號:
g_MakeCallRequestID = lineMakeCall (g_CurrentLineInfo.hLine,
&g_hCall,
szDialablePhoneNum,
0,
lpCallParams);
if (g_MakeCallRequestID > 0)
{
g_bCurrentLineAvail = FALSE;
DialogBoxParam (g_hInst,
MAKEINTRESOURCE(IDD_DIALING),
g_hwndMain,
(DLGPROC) DialingProc, 0);
}
else
{//關閉線路
CurrentLineClose ();
}
......
return;
}
//為確定線路的狀態(tài),發(fā)生的事件而必須提供的回調(diào)函數(shù),
VOID CALLBACK lineCallbackFunc (DWORD hDevice,
DWORD dwMsg,
DWORD dwCallbackInstance,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3)
{
LPTSTR lpszStatus;
switch (dwMsg)
{
case LINE_CALLSTATE:
if (g_hCall != (HCALL) hDevice) return;
switch (dwParam1)
{
case LINECALLSTATE_DIALING:
lpszStatus = TEXT("撥號");
break;
case LINECALLSTATE_PROCEEDING:
lpszStatus = TEXT("撥號完畢,正在呼叫")
break;
case LINECALLSTATE_CONNECTED:
lpszStatus = TEXT("線路接上");
break;
case LINECALLSTATE_BUSY:
ErrorBox (TEXT("線路忙, 關閉"));
CurrentLineClose ();
if (g_hwndDial)
SendMessage (g_hwndDial, WM_COMMAND, MAKEWPARAM(IDOK,0), 0);
break;
......
}
break;
default:
break;
}
}
//關閉當前線路函數(shù):
VOID CurrentLineClose ()
{
if (g_CurrentLineInfo.hLine)
lineClose (g_CurrentLineInfo.hLine);
g_CurrentLineInfo.hLine = NULL;
g_bCurrentLineAvail = TRUE;
g_hCall = NULL;
}
//獲取線路信息
DWORD GetLineInfo (DWORD dwLineID, LPLINEINFO LineInfo)
{
DWORD dwSize, dwReturn;
LPTSTR lpszLineName = NULL;
LPLINEDEVCAPS lpLineDevCaps = NULL;
//協(xié)商TAPI版本號
if (dwReturn = lineNegotiateAPIVersion (
g_hLineApp, dwLineID, TAPI_VERSION_1_0, TAPI_CURRENT_VERSION, &(lpLineInfo->dwAPIVersion), NULL))
{
goto exit;
}
dwSize = sizeof (LINEDEVCAPS);
do
{
if (!(lpLineDevCaps = (LPLINEDEVCAPS) LocalAlloc (LPTR, dwSize)))
{
dwReturn = LINEERR_NOMEM;
goto exit;
}
lpLineDevCaps->dwTotalSize = dwSize;
//獲取指定邏輯線路設備的能力。
if (dwReturn = lineGetDevCaps (g_hLineApp,
dwLineID, lpLineInfo->dwAPIVersion, 0, lpLineDevCaps))
{
goto exit;
}
if (lpLineDevCaps->dwNeededSize <= lpLineDevCaps->dwTotalSize)
break;
dwSize = lpLineDevCaps->dwNeededSize;
LocalFree (lpLineDevCaps);
lpLineDevCaps = NULL;
} while (TRUE);
lpLineInfo->dwPermanentLineID = lpLineDevCaps->dwPermanentLineID;
......
dwReturn = ERR_NONE;
exit:
if (lpLineDevCaps)
LocalFree (lpLineDevCaps);
if (lpszLineName)
LocalFree (lpszLineName);
return dwReturn;
}
以上代碼在Visual C++ 5.0及WCE Toolkit for Visual C++ 5.0下調(diào)試通過。