Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1356 lines
40 KiB

/*==========================================================================
*
* Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved.
*
* File: dial.c
* Content: Wrappers for TAPI routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 6/10/96 kipo created it
* 6/22/96 kipo close com port when disconnected; allow checking for
* valid TAPI lines during NewComPort().
* 7/08/96 kipo added support for new dialogs
* 8/10/96 kipo added support for dialing location
* 1/06/97 kipo updated for objects
* 1/24/97 kipo bug #5400: Compaq Presario was overwriting the dev caps
* buffer, causing a crash. Fixed to allocated a larger
* buffer with some slop as a workaround.
* 3/04/97 kipo close com port handle when deallocating call; use string
* table for modem strings; updated debug output.
* 3/24/97 kipo added support for specifying which modem to use
* 4/08/97 kipo added support for separate modem and serial baud rates
* 5/07/97 kipo added support for modem choice list
* 5/23/97 kipo added support return status codes
* 4/21/98 a-peterz #22920 Handle LINE_CLOSE message
* 5/07/98 a-peterz #15251 Track call errors in DPDIAL
* 10/13/99 johnkan #413516 - Mismatch between modem dialog selection and TAPI device ID
*@@END_MSINTERNAL
***************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include "dputils.h"
#include "macros.h"
#include "dial.h"
void FAR PASCAL LineCallBackProc(DWORD hDevice, DWORD dwMessage, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwParam3);
void ProcessConnectedState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege);
void ProcessDisconnectedState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege);
void ProcessIdleState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege);
void ProcessOfferingState(LPDPDIAL globals, HCALL hCall, DWORD dwCallPrivilege);
void ProcessReplyMessage(LPDPDIAL globals, DWORD asyncID, LINERESULT lResult);
LINERESULT dialGetDevCaps(LPDPDIAL globals, DWORD dwLine, DWORD dwAPIVersion, LPLINEDEVCAPS *lpDevCapsRet);
LINERESULT dialGetCommHandle(LPDPDIAL globals);
LINERESULT dialCloseCommHandle(LPDPDIAL globals);
LINERESULT dialTranslateAddress(LPDPDIAL globals, DWORD dwDeviceID, DWORD dwAPIVersion,
LPCSTR lpszDialAddress,
LPLINETRANSLATEOUTPUT *lpLineTranslateOutputRet);
LPSTR GetLineErrStr(LONG err);
LPSTR GetCallStateStr(DWORD callState);
LPSTR GetLineMsgStr(DWORD msg);
#ifdef DEBUG
extern LONG lineError(LONG err, LPSTR modName, DWORD lineNum);
#define LINEERROR(err) (lineError(err, DPF_MODNAME, __LINE__))
#else
#define LINEERROR(err) (err)
#endif
/* dial initialize */
#undef DPF_MODNAME
#define DPF_MODNAME "dialInitialize"
LINERESULT dialInitialize(HINSTANCE hInst, LPTSTR szAppName,
LPDPCOMPORT lpComPort, LPDPDIAL *storage)
{
LPDPDIAL globals;
LINERESULT lResult; /* Stores return code from TAPI calls */
// create globals
globals =(LPDPDIAL) GlobalAllocPtr(GHND, sizeof(DPDIAL));
FAILWITHACTION(globals == NULL, lResult = LINEERR_NOMEM, Failure);
DPF(3, "lineInitialize");
DPF(3, "> hInstance: %08X", hInst);
DPF(3, "> szAppName: %s", szAppName);
// init the line
lResult = lineInitialize(&globals->hLineApp,
hInst,
LineCallBackProc,
szAppName,
&globals->dwNumLines);
FAILIF(LINEERROR(lResult), Failure);
DPF(3, "< hLineApp: %08X", globals->hLineApp);
DPF(3, "< dwNumLines: %d", globals->dwNumLines);
// no lines available
FAILWITHACTION(globals->dwNumLines == 0, lResult = LINEERR_NODEVICE, Failure);
// store pointer to com port object
globals->lpComPort = lpComPort;
*storage = globals;
return (SUCCESS);
Failure:
dialShutdown(globals);
return (lResult);
}
/* dial shutdown */
#undef DPF_MODNAME
#define DPF_MODNAME "dialShutdown"
LINERESULT dialShutdown(LPDPDIAL globals)
{
LINERESULT lResult;
if (globals == NULL)
return (SUCCESS);
if (globals->hLineApp)
{
dialDropCall(globals);
dialDeallocCall(globals);
dialLineClose(globals);
DPF(3, "lineShutdown");
DPF(3, "> hLineApp: %08X", globals->hLineApp);
lResult = lineShutdown(globals->hLineApp);
LINEERROR(lResult);
}
GlobalFreePtr(globals);
return (SUCCESS);
}
/* dialLineOpen - wrapper for lineOpen */
#undef DPF_MODNAME
#define DPF_MODNAME "dialLineOpen"
LINERESULT dialLineOpen(LPDPDIAL globals, DWORD dwLine)
{
LINEEXTENSIONID lineExtensionID; // Will be set to 0 to indicate no known extensions
LPLINEDEVCAPS lpLineDevCaps = NULL;
LINERESULT lResult;
// fail if line is already open
FAILWITHACTION(globals->hLine != 0, lResult = LINEERR_INVALLINEHANDLE, Failure);
/* negotiate API version for each line */
lResult = lineNegotiateAPIVersion(globals->hLineApp, dwLine,
TAPIVERSION, TAPIVERSION,
&globals->dwAPIVersion, &lineExtensionID);
FAILIF(LINEERROR(lResult), Failure);
lResult = dialGetDevCaps(globals, dwLine, globals->dwAPIVersion, &lpLineDevCaps);
FAILIF(LINEERROR(lResult), Failure);
/* check for supported media mode. If not datamodem, continue to next line */
FAILWITHACTION(!(lpLineDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM),
lResult = LINEERR_NODEVICE, Failure);
DPF(3, "lineOpen");
DPF(3, "> hLineApp: %08X", globals->hLineApp);
DPF(3, "> dwDeviceID: %d", dwLine);
// reset error tracking
globals->dwCallError = CALL_OK;
/* open the line that supports data modems */
lResult = lineOpen( globals->hLineApp, dwLine, &globals->hLine,
globals->dwAPIVersion, 0L,
(DWORD_PTR) globals,
LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_DATAMODEM,
NULL);
FAILIF(LINEERROR(lResult), Failure);
DPF(3, "< hLine: %08X", globals->hLine);
/* if we are here then we found a compatible line */
globals->dwLineID = dwLine;
globals->dwCallState = LINECALLSTATE_IDLE; // line is now idle and ready to make/receive calls
lResult = SUCCESS;
Failure:
if (lpLineDevCaps)
GlobalFreePtr(lpLineDevCaps);
return (lResult);
}
/* dialLineClose - wrapper for lineClose */
#undef DPF_MODNAME
#define DPF_MODNAME "dialLineClose"
LINERESULT dialLineClose(LPDPDIAL globals)
{
LINERESULT lResult;
// fail if line is already closed
FAILWITHACTION(globals->hLine == 0, lResult = LINEERR_INVALLINEHANDLE, Failure);
DPF(3, "lineClose");
DPF(3, "> hLine: %08X", globals->hLine);
lResult = lineClose(globals->hLine);
LINEERROR(lResult);
globals->hLine = 0;
Failure:
return (lResult);
}
/* dialMakeCall - wrapper for lineMakeCall */
#undef DPF_MODNAME
#define DPF_MODNAME "dialMakeCall"
LINERESULT dialMakeCall(LPDPDIAL globals, LPTSTR szDestination)
{
LINECALLPARAMS callparams;
LINERESULT lResult;
// fail if line not open or if call is already open
FAILWITHACTION(globals->hLine == 0, lResult = LINEERR_INVALLINEHANDLE, Failure);
FAILWITHACTION(globals->hCall != 0, lResult = LINEERR_INVALCALLHANDLE, Failure);
// set call parameters
ZeroMemory(&callparams, sizeof(LINECALLPARAMS));
callparams.dwBearerMode = LINEBEARERMODE_VOICE;
callparams.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
callparams.dwTotalSize = sizeof(LINECALLPARAMS);
DPF(3, "lineMakeCall");
DPF(3, "> hLine: %08X", globals->hLine);
DPF(3, "> szDestAddr: \"%s\"", szDestination);
lResult = lineMakeCall(globals->hLine, &globals->hCall, szDestination, 0, &callparams);
// lResult will be > 0 if call is asynchronous
FAILWITHACTION(lResult < 0, LINEERROR(lResult), Failure);
FAILMSG(lResult == 0);
DPF(3, "< hCall: %08X", globals->hCall);
DPF(3, "< dwAsyncID: %d", lResult);
globals->dwAsyncID = lResult; // store async ID
lResult = SUCCESS;
Failure:
return (lResult);
}
/* dialDropCall - wrapper for lineDrop */
#undef DPF_MODNAME
#define DPF_MODNAME "dialDropCall"
LINERESULT dialDropCall(LPDPDIAL globals)
{
MSG msg;
DWORD dwStopTicks;
LINERESULT lResult;
// fail if line not open or if call not open
FAILWITHACTION(globals->hLine == 0, lResult = LINEERR_INVALLINEHANDLE, Failure);
FAILWITHACTION(globals->hCall == 0, lResult = LINEERR_INVALCALLHANDLE, Failure);
DPF(3, "lineDrop");
DPF(3, "> hCall: %08X", globals->hCall);
lResult = lineDrop(globals->hCall, NULL, 0);
// lResult will be > 0 if call is asynchronous
FAILWITHACTION(lResult < 0, LINEERROR(lResult), Failure);
FAILMSG(lResult == 0);
DPF(3, "< dwAsyncID: %d", lResult);
globals->dwAsyncID = lResult; // store async ID
// wait for call to get dropped
dwStopTicks = GetTickCount() + LINEDROPTIMEOUT;
while (GetTickCount() < dwStopTicks)
{
// see if reply has occured and we are idle
if ((globals->dwAsyncID == 0) &&
(globals->dwCallState == LINECALLSTATE_IDLE))
{
break;
}
// give TAPI a chance to call our callback
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
lResult = SUCCESS;
Failure:
return (lResult);
}
/* dialDeallocCall - wrapper for lineDeallocCall */
#undef DPF_MODNAME
#define DPF_MODNAME "dialDeallocCall"
LINERESULT dialDeallocCall(LPDPDIAL globals)
{
LINERESULT lResult;
// fail if line not open or if call not open
FAILWITHACTION(globals->hLine == 0, lResult = LINEERR_INVALLINEHANDLE, Failure);
FAILWITHACTION(globals->hCall == 0, lResult = LINEERR_INVALCALLHANDLE, Failure);
// close the com port
dialCloseCommHandle(globals);
DPF(3, "lineDeallocateCall");
DPF(3, "> hCall: %08X", globals->hCall);
lResult = lineDeallocateCall(globals->hCall);
LINEERROR(lResult);
globals->hCall = 0;
Failure:
return (lResult);
}
/* dialIsConnected- returns TRUE if call is connected */
#undef DPF_MODNAME
#define DPF_MODNAME "dialIsConnected"
BOOL dialIsConnected(LPDPDIAL globals)
{
// connected if we have a call handle and the state is connected
if ((globals->hCall) &&
(globals->dwCallState == LINECALLSTATE_CONNECTED))
return (TRUE);
else
return (FALSE);
}
/* callback function */
#undef DPF_MODNAME
#define DPF_MODNAME "LineCallBackProc"
void FAR PASCAL LineCallBackProc(DWORD hDevice, DWORD dwMessage, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwParam3)
{
LPDPDIAL globals = (LPDPDIAL) dwInstance;
DPF(3, "Line message: %s", GetLineMsgStr(dwMessage));
switch (dwMessage)
{
case LINE_LINEDEVSTATE:
break;
case LINE_CALLSTATE:
globals->dwCallState = dwParam1;
DPF(3, " call state: %s", GetCallStateStr((DWORD)globals->dwCallState));
switch (globals->dwCallState)
{
case LINECALLSTATE_OFFERING:
ProcessOfferingState(globals, (HCALL) hDevice, (DWORD)dwParam3);
break;
case LINECALLSTATE_CONNECTED:
ProcessConnectedState(globals, (HCALL) hDevice, (DWORD)dwParam2, (DWORD)dwParam3);
break;
case LINECALLSTATE_DISCONNECTED:
ProcessDisconnectedState(globals, (HCALL) hDevice, (DWORD)dwParam2, (DWORD)dwParam3);
break;
case LINECALLSTATE_IDLE:
ProcessIdleState(globals, (HCALL) hDevice, (DWORD)dwParam2, (DWORD)dwParam3);
break;
case LINECALLSTATE_BUSY:
break;
}
break;
case LINE_REPLY:
ProcessReplyMessage(globals, (DWORD)dwParam1, (LINERESULT) dwParam2);
break;
/* other messages that can be processed */
case LINE_CLOSE:
// the line has shut itself down
globals->hLine = 0;
globals->dwCallError = CALL_CLOSED;
break;
case LINE_ADDRESSSTATE:
break;
case LINE_CALLINFO:
break;
case LINE_DEVSPECIFIC:
break;
case LINE_DEVSPECIFICFEATURE:
break;
case LINE_GATHERDIGITS:
break;
case LINE_GENERATE:
break;
case LINE_MONITORDIGITS:
break;
case LINE_MONITORMEDIA:
break;
case LINE_MONITORTONE:
break;
} /* switch */
} /* LineCallBackProc */
/* ProcessOfferingState - handler for LINECALLSTATE_OFFERING state */
#undef DPF_MODNAME
#define DPF_MODNAME "ProcessOfferingState"
void ProcessOfferingState(LPDPDIAL globals, HCALL hCall, DWORD dwCallPrivilege)
{
LINERESULT lResult;
DDASSERT(hCall);
DDASSERT(globals->hCall == 0);
DDASSERT(globals->dwAsyncID == 0);
DPF(3, " hCall: %08X", hCall);
DPF(3, " privilege: %08X", (DWORD)dwCallPrivilege);
// fail if we don't own the call
FAILIF(dwCallPrivilege != LINECALLPRIVILEGE_OWNER, Failure);
// answer the call
lResult = lineAnswer(hCall, NULL, 0);
// lResult will be > 0 if call is asynchronous
FAILWITHACTION(lResult < 0, LINEERROR(lResult), Failure);
FAILMSG(lResult == 0);
globals->hCall = hCall; // store call handle
globals->dwAsyncID = lResult; // store async ID
Failure:
return;
}
/* ProcessConnectedState - handler for LINECALLSTATE_CONNECTED state */
#undef DPF_MODNAME
#define DPF_MODNAME "ProcessConnectedState"
void ProcessConnectedState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege)
{
LINERESULT lResult;
HRESULT hr;
DDASSERT(hCall);
DDASSERT(globals->hCall);
DDASSERT(globals->hCall == hCall);
DPF(3, " hCall: %08X", hCall);
DPF(3, " privilege: %08X", dwCallPrivilege);
DPF(3, " detail: %08X", dwCallStateDetail);
// get the id of the COM device connected to the modem
// NOTE: once we get the handle, it is our responsibility to close it
lResult = dialGetCommHandle(globals);
FAILIF(LINEERROR(lResult), Failure);
DPF(3, " hComPort: %08X", globals->hComm);
// setup com port
hr = globals->lpComPort->Setup(globals->lpComPort, globals->hComm);
FAILIF(FAILED(hr), Failure);
{
DWORD dwBaudRate;
lResult = dialGetBaudRate(globals, &dwBaudRate);
}
Failure:
return;
}
/* ProcessDisconnectedState - handler for LINECALLSTATE_DISCONNECTED state */
#undef DPF_MODNAME
#define DPF_MODNAME "ProcessDisconnectedState"
void ProcessDisconnectedState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege)
{
LINERESULT lResult;
DDASSERT(hCall);
DDASSERT(globals->hCall);
DDASSERT(globals->hCall == hCall);
DPF(3, " hCall: %08X", hCall);
DPF(3, " privilege: %08X", dwCallPrivilege);
DPF(3, " detail: %08X", dwCallStateDetail);
// record error
globals->dwCallError = CALL_DISCONNECTED;
// shutdown com port and deallocate call handle
lResult = dialDeallocCall(globals);
FAILMSG(LINEERROR(lResult));
}
/* ProcessIdleState - handler for LINECALLSTATE_IDLE state */
#undef DPF_MODNAME
#define DPF_MODNAME "ProcessIdleState"
void ProcessIdleState(LPDPDIAL globals, HCALL hCall, DWORD dwCallStateDetail, DWORD dwCallPrivilege)
{
DDASSERT(hCall);
DPF(3, " hCall: %08X", hCall);
DPF(3, " privilege: %08X", dwCallPrivilege);
DPF(3, " detail: %08X", dwCallStateDetail);
}
/* ProcessReplyMessage - handler for LINE_REPLY message */
#undef DPF_MODNAME
#define DPF_MODNAME "ProcessReplyMessage"
void ProcessReplyMessage(LPDPDIAL globals, DWORD dwAsyncID, LINERESULT lResult)
{
DDASSERT(dwAsyncID);
DDASSERT(globals->dwAsyncID);
DDASSERT(globals->dwAsyncID == dwAsyncID);
DPF(3, " dwAsyncID: %d", dwAsyncID);
DPF(3, " error: %d", lResult);
// check for an error
if (LINEERROR(lResult))
globals->dwCallError = CALL_LINEERROR;
// reset field so we know reply happened
globals->dwAsyncID = 0;
}
/* dialGetDevCaps - wrapper for lineGetDevCaps */
/* Bug #5400 -
My trusty Compaq Presario returns two line devices. The second device says it
needs 555 bytes for dev caps, but when you give it a pointer to a 555-byte block
it actually writes 559 (!) bytes into the buffer! Whoah, Bessy!
This makes Windows very unhappy in strange and magical ways.
The fix is to start with a very large buffer (1024 bytes?) like all the samples do
and then leave some slop in subsequent reallocs, which should hopefully clean up
after these messy critters.
*/
#define DEVCAPSINITIALSIZE 1024 // size of first alloc
#define DEVCAPSSLOP 100 // extra space that loser service providers can party on
#undef DPF_MODNAME
#define DPF_MODNAME "dialGetDevCaps"
LINERESULT dialGetDevCaps(LPDPDIAL globals, DWORD dwLine, DWORD dwAPIVersion, LPLINEDEVCAPS *lpDevCapsRet)
{
LPLINEDEVCAPS lpDevCaps;
LINERESULT lResult;
LPVOID lpTemp;
// create a buffer for dev caps
lpDevCaps = (LPLINEDEVCAPS) GlobalAllocPtr(GHND, DEVCAPSINITIALSIZE + DEVCAPSSLOP);
FAILWITHACTION(lpDevCaps == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpDevCaps->dwTotalSize = DEVCAPSINITIALSIZE;
while (TRUE)
{
// get device caps
lResult = lineGetDevCaps(globals->hLineApp, dwLine,
dwAPIVersion, 0, lpDevCaps);
if (lResult == SUCCESS)
{
// make sure there is enough space
if (lpDevCaps->dwNeededSize <= lpDevCaps->dwTotalSize)
break; // there is enough space, so exit
}
else if (lResult != LINEERR_STRUCTURETOOSMALL)
{
LINEERROR(lResult);
goto Failure;
}
// reallocate buffer if not big enough */
lpTemp = GlobalReAllocPtr(lpDevCaps, lpDevCaps->dwNeededSize + DEVCAPSSLOP, 0);
FAILWITHACTION(lpTemp == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpDevCaps = lpTemp;
lpDevCaps->dwTotalSize = lpDevCaps->dwNeededSize;
}
*lpDevCapsRet = lpDevCaps;
return (SUCCESS);
Failure:
if (lpDevCaps)
GlobalFreePtr(lpDevCaps);
return (lResult);
}
/* dialGetCallInfo - wrapper for lineGetCallInfo */
#undef DPF_MODNAME
#define DPF_MODNAME "dialGetCallInfo"
LINERESULT dialGetCallInfo(LPDPDIAL globals, LPLINECALLINFO *lpCallInfoRet)
{
LPLINECALLINFO lpCallInfo;
LINERESULT lResult;
LPVOID lpTemp;
// create a buffer for call info
lpCallInfo = (LPLINECALLINFO) GlobalAllocPtr(GHND, sizeof(LINECALLINFO));
FAILWITHACTION(lpCallInfo == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpCallInfo->dwTotalSize = sizeof(LINECALLINFO);
while (TRUE)
{
// get device info
lResult = lineGetCallInfo(globals->hCall, lpCallInfo);
if (lResult == SUCCESS)
{
// make sure there is enough space
if (lpCallInfo->dwNeededSize <= lpCallInfo->dwTotalSize)
break; // there is enough space, so exit
}
else if (lResult != LINEERR_STRUCTURETOOSMALL)
{
LINEERROR(lResult);
goto Failure;
}
// reallocate buffer if not big enough */
lpTemp = GlobalReAllocPtr(lpCallInfo, lpCallInfo->dwNeededSize, 0);
FAILWITHACTION(lpTemp == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpCallInfo = lpTemp;
lpCallInfo->dwTotalSize = lpCallInfo->dwNeededSize;
}
*lpCallInfoRet = lpCallInfo;
return (SUCCESS);
Failure:
if (lpCallInfo)
GlobalFreePtr(lpCallInfo);
return (lResult);
}
/* dialGetBaudRate - get baud rate of current connecton */
#undef DPF_MODNAME
#define DPF_MODNAME "dialGetBaudRate"
LINERESULT dialGetBaudRate(LPDPDIAL globals, LPDWORD lpdwBaudRate)
{
LPLINECALLINFO lpCallInfo;
LINERESULT lResult;
lResult = dialGetCallInfo(globals, &lpCallInfo);
if LINEERROR(lResult)
return (lResult);
*lpdwBaudRate = lpCallInfo->dwRate;
GlobalFreePtr(lpCallInfo);
return (SUCCESS);
}
/* dialGetTranslateCaps - wrapper for lineGetTranslateCaps */
#undef DPF_MODNAME
#define DPF_MODNAME "dialGetTranslateCaps"
LINERESULT dialGetTranslateCaps(LPDPDIAL globals, DWORD dwAPIVersion, LPLINETRANSLATECAPS *lpTranslateCapsRet)
{
LPLINETRANSLATECAPS lpTranslateCaps;
LPVOID lpTemp;
LINERESULT lResult;
// create a buffer for translate caps
lpTranslateCaps = (LPLINETRANSLATECAPS) GlobalAllocPtr(GHND, sizeof(LINETRANSLATECAPS));
FAILWITHACTION(lpTranslateCaps == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpTranslateCaps->dwTotalSize = sizeof(LINETRANSLATECAPS);
while (TRUE)
{
// get translate caps
lResult = lineGetTranslateCaps(globals->hLineApp, dwAPIVersion, lpTranslateCaps);
if (lResult == SUCCESS)
{
// make sure there is enough space
if (lpTranslateCaps->dwNeededSize <= lpTranslateCaps->dwTotalSize)
break; // there is enough space, so exit
}
else if (lResult != LINEERR_STRUCTURETOOSMALL)
{
LINEERROR(lResult);
goto Failure;
}
// reallocate buffer if not big enough */
lpTemp = GlobalReAllocPtr(lpTranslateCaps, lpTranslateCaps->dwNeededSize, 0);
FAILWITHACTION(lpTemp == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpTranslateCaps = lpTemp;
lpTranslateCaps->dwTotalSize = lpTranslateCaps->dwNeededSize;
}
*lpTranslateCapsRet = lpTranslateCaps;
return (SUCCESS);
Failure:
if (lpTranslateCaps)
GlobalFreePtr(lpTranslateCaps);
return (lResult);
}
/* dialGetCommHandle - wrapper for lineGetID */
#undef DPF_MODNAME
#define DPF_MODNAME "dialGetCommHandle"
/* structure returned by Unimodem which contains device handle and name */
typedef struct {
HANDLE hComm;
CHAR szDeviceName[1];
} COMMID, *LPCOMMID;
LINERESULT dialGetCommHandle(LPDPDIAL globals)
{
LPCOMMID lpCommID;
VARSTRING *vs, *temp;
LINERESULT lResult;
vs = (VARSTRING *) GlobalAllocPtr(GHND, sizeof(VARSTRING));
FAILWITHACTION(vs == NULL, lResult = LINEERR_NOMEM, Failure);
vs->dwTotalSize = sizeof(VARSTRING);
vs->dwStringFormat = STRINGFORMAT_BINARY;
while (TRUE)
{
// get line ID
lResult = lineGetID(0, 0L, globals->hCall, LINECALLSELECT_CALL, vs, "comm/datamodem");
if (lResult == SUCCESS)
{
// make sure there is enough space
if (vs->dwNeededSize <= vs->dwTotalSize)
break; // there is enough space, so exit
}
else if (lResult != LINEERR_STRUCTURETOOSMALL)
{
LINEERROR(lResult);
goto Failure;
}
// reallocate buffer if not big enough */
temp = GlobalReAllocPtr(vs, vs->dwNeededSize, 0);
FAILWITHACTION(temp == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
vs = temp;
vs->dwTotalSize = vs->dwNeededSize;
}
lpCommID = (LPCOMMID) ((LPSTR)vs + vs->dwStringOffset);
// lstrcpy(globals->szDeviceName, cid->szDeviceName);
globals->hComm = lpCommID->hComm;
Failure:
if (vs)
GlobalFreePtr(vs);
return (lResult);
}
/* dialCloseCommHandle - make sure com port is closed */
/* NOTE: As per the docs for the "comm/datamodem" device class,
the handle to the com port returned by lineGetID() MUST be explictly
closed using CloseHandle() or you will not be able to to open this
line again!
*/
#undef DPF_MODNAME
#define DPF_MODNAME "dialCloseCommHandle"
LINERESULT dialCloseCommHandle(LPDPDIAL globals)
{
HANDLE hCom;
// make sure the com port globals are available
if (globals->lpComPort)
{
// get handle to com port
hCom = globals->lpComPort->GetHandle(globals->lpComPort);
// make sure its closed down
if (hCom)
{
globals->lpComPort->Shutdown(globals->lpComPort);
CloseHandle(hCom);
}
}
return (SUCCESS);
}
/* dialTranslateAddress - wrapper for lineTranslateAddress */
#undef DPF_MODNAME
#define DPF_MODNAME "dialTranslateAddress"
LINERESULT dialTranslateAddress(LPDPDIAL globals, DWORD dwDeviceID, DWORD dwAPIVersion,
LPCSTR lpszDialAddress,
LPLINETRANSLATEOUTPUT *lpLineTranslateOutputRet)
{
LPLINETRANSLATEOUTPUT lpLineTranslateOutput;
LPVOID lpTemp;
LINERESULT lResult;
// create a buffer for translate caps
lpLineTranslateOutput = (LPLINETRANSLATEOUTPUT) GlobalAllocPtr(GHND, sizeof(LINETRANSLATEOUTPUT));
FAILWITHACTION(lpLineTranslateOutput == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpLineTranslateOutput->dwTotalSize = sizeof(LINETRANSLATEOUTPUT);
while (TRUE)
{
// translate address
lResult = lineTranslateAddress(globals->hLineApp, dwDeviceID, dwAPIVersion,
lpszDialAddress, 0, LINETRANSLATEOPTION_CANCELCALLWAITING,
lpLineTranslateOutput);
if (lResult == SUCCESS)
{
// make sure there is enough space
if (lpLineTranslateOutput->dwNeededSize <= lpLineTranslateOutput->dwTotalSize)
break; // there is enough space, so exit
}
else if (lResult != LINEERR_STRUCTURETOOSMALL)
{
LINEERROR(lResult);
goto Failure;
}
// reallocate buffer if not big enough */
lpTemp = GlobalReAllocPtr(lpLineTranslateOutput, lpLineTranslateOutput->dwNeededSize, 0);
FAILWITHACTION(lpTemp == NULL, lResult = LINEERROR(LINEERR_NOMEM), Failure);
lpLineTranslateOutput = lpTemp;
lpLineTranslateOutput->dwTotalSize = lpLineTranslateOutput->dwNeededSize;
}
*lpLineTranslateOutputRet = lpLineTranslateOutput;
return (SUCCESS);
Failure:
if (lpLineTranslateOutput)
GlobalFreePtr(lpLineTranslateOutput);
return (lResult);
}
LINERESULT dialTranslateDialog(LPDPDIAL globals, HWND hWnd,
DWORD dwDeviceID, LPTSTR szPhoneNumber)
{
LINERESULT lResult;
lResult = lineTranslateDialog(globals->hLineApp, dwDeviceID,
TAPIVERSION, hWnd, szPhoneNumber);
return (lResult);
}
//
// FUNCTION: void dialFillModemComboBox(HWND)
//
// PURPOSE: Fills the modem control with the available line devices.
//
// PARAMETERS:
// hwndDlg - handle to the current "Dial" dialog
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
// This function enumerates through all the TAPI line devices and
// queries each for the device name. The device name is then put into
// the 'TAPI Line' control. These device names are kept in order rather
// than sorted. This allows "Dial" to know which device ID the user
// selected just by the knowing the index of the selected string.
//
// There are default values if there isn't a device name, if there is
// an error on the device, or if the device name is an empty string.
// The device name is also checked to make sure it is null terminated.
//
// Note that a Legacy API Version is negotiated. Since the fields in
// the LINEDEVCAPS structure that we are interested in haven't moved, we
// can negotiate a lower API Version than this sample is designed for
// and still be able to access the necessary structure members.
//
// The first line that is usable by TapiComm is selected as the 'default'
// line. Also note that if there was a previously selected line, this
// remains the default line. This would likely only occur if this
// function is called after the dialog has initialized once; for example,
// if a new line is added.
//
//
LINERESULT dialGetModemName(LPDPDIAL globals, DWORD dwDeviceID,
LPSTR lpszModemName, DWORD dwModemNameSize)
{
LPLINEDEVCAPS lpLineDevCaps = NULL;
LPSTR lpszLineName;
LINEEXTENSIONID lineExtensionID; // Will be set to 0 to indicate no known extensions
DWORD dwAPIVersion; // api version
DWORD dwStrSize;
LINERESULT lResult;
/* negotiate API version for each line */
lResult = lineNegotiateAPIVersion(globals->hLineApp, dwDeviceID,
TAPIVERSION, TAPIVERSION,
&dwAPIVersion, &lineExtensionID);
if LINEERROR(lResult)
goto FAILURE;
lResult = dialGetDevCaps(globals, dwDeviceID, dwAPIVersion, &lpLineDevCaps);
if LINEERROR(lResult)
goto FAILURE;
if ((lpLineDevCaps->dwLineNameSize) &&
(lpLineDevCaps->dwLineNameOffset) &&
(lpLineDevCaps->dwStringFormat == STRINGFORMAT_ASCII))
{
// This is the name of the device.
lpszLineName = ((char *) lpLineDevCaps) + lpLineDevCaps->dwLineNameOffset;
if (lpszLineName[0] != '\0')
{
// Reverse indented to make this fit
// Make sure the device name is null terminated.
if (lpszLineName[lpLineDevCaps->dwLineNameSize -1] != '\0')
{
// If the device name is not null terminated, null
// terminate it. Yes, this looses the end character.
// Its a bug in the service provider.
lpszLineName[lpLineDevCaps->dwLineNameSize-1] = '\0';
DPF(0, "Device name for device 0x%lx is not null terminated.", dwDeviceID);
}
}
else // Line name started with a NULL.
{
lResult = LINEERR_OPERATIONFAILED;
goto FAILURE;
}
}
else // DevCaps doesn't have a valid line name. Unnamed.
{
lResult = LINEERR_OPERATIONFAILED;
goto FAILURE;
}
// return modem name (make sure it fits)
dwStrSize = strlen(lpszLineName) + 1;
if (dwStrSize <= dwModemNameSize)
CopyMemory(lpszModemName, lpszLineName, dwStrSize);
else
{
CopyMemory(lpszModemName, lpszLineName, dwModemNameSize - 1);
lpszModemName[dwModemNameSize - 1] = '\0';
}
FAILURE:
if (lpLineDevCaps)
GlobalFreePtr(lpLineDevCaps);
return (lResult);
}
LINERESULT dialGetModemList(LPDPDIAL globals, BOOL bAnsi, LPVOID *lplpData, LPDWORD lpdwDataSize)
{
DWORD dwDeviceID;
CHAR szModemName[MAXSTRINGSIZE];
LPBYTE lpData;
DWORD dwDataSize, dwStrBytes, dwStrLen;
LINERESULT lResult;
// make space for all possible strings plus terminating null
lpData = (LPBYTE) GlobalAllocPtr(GHND, globals->dwNumLines * MAXSTRINGSIZE * sizeof(WCHAR) + sizeof(WCHAR));
FAILWITHACTION(lpData == NULL, lResult = LINEERR_NOMEM, Failure);
dwDataSize = 0;
for (dwDeviceID = 0; dwDeviceID < globals->dwNumLines; dwDeviceID ++)
{
lResult = dialGetModemName(globals, dwDeviceID, szModemName, MAXSTRINGSIZE);
if LINEERROR(lResult)
continue;
if (bAnsi)
{
dwStrBytes = (lstrlen(szModemName) + 1) * sizeof(CHAR);
memcpy(lpData + dwDataSize, szModemName, dwStrBytes);
}
else
{
// NOTE: AnsiToWide returns the character count INCLUDING the terminating null character
dwStrLen = AnsiToWide((LPWSTR) (lpData + dwDataSize), szModemName, MAXSTRINGSIZE * sizeof(WCHAR));
dwStrBytes = dwStrLen * sizeof(WCHAR);
}
dwDataSize += dwStrBytes;
}
// put a null at end of list to terminate it
if (bAnsi)
{
*(lpData + dwDataSize) = 0;
dwDataSize += sizeof(CHAR);
}
else
{
*((LPWSTR) (lpData + dwDataSize)) = 0;
dwDataSize += sizeof(WCHAR);
}
// return buffer pointer and size
*lplpData = lpData;
*lpdwDataSize = dwDataSize;
return (SUCCESS);
Failure:
return (lResult);
}
void dialFillModemComboBox(LPDPDIAL globals, HWND hwndDlg, int item, DWORD dwDefaultDevice)
{
DWORD dwDeviceID;
CHAR szModemName[MAXSTRINGSIZE];
LINERESULT lResult;
for (dwDeviceID = 0; dwDeviceID < globals->dwNumLines; dwDeviceID ++)
{
//
// Attempt to get the modem name. If this fails, don't add the modem
// to the dialog.
//
lResult = dialGetModemName(globals, dwDeviceID, szModemName, MAXSTRINGSIZE);
if ( LINEERROR(lResult) == FALSE )
{
//
// This line appears to be usable, put the device name into the
// dialog control and associate the TAPI modem ID with it
//
lResult = (DWORD) SendDlgItemMessage(hwndDlg, item,
CB_ADDSTRING, 0, (LPARAM) szModemName);
if ( lResult != CB_ERRSPACE )
{
DWORD_PTR TempReturn;
//
// We've managed to get this entry into the control, make sure
// we associate the proper TAPI modem ID with this item. This
// should never fail.
//
TempReturn = SendDlgItemMessage( hwndDlg, item, CB_SETITEMDATA, lResult, dwDeviceID );
DDASSERT( TempReturn != CB_ERR );
// If this line is usable and we don't have a default initial
// line yet, make this the initial line.
if (dwDefaultDevice == MAXDWORD)
dwDefaultDevice = lResult;
}
}
}
if (dwDefaultDevice == MAXDWORD)
dwDefaultDevice = 0;
// Set the initial default line
SendDlgItemMessage(hwndDlg, item,
CB_SETCURSEL, dwDefaultDevice, 0);
}
LRESULT dialGetDeviceIDFromName(LPDPDIAL globals, LPCSTR szTargetName, DWORD *lpdwDeviceID)
{
DWORD dwDeviceID;
CHAR szModemName[MAXSTRINGSIZE];
LINERESULT lResult;
for (dwDeviceID = 0; dwDeviceID < globals->dwNumLines; dwDeviceID ++)
{
lResult = dialGetModemName(globals, dwDeviceID, szModemName, MAXSTRINGSIZE);
if LINEERROR(lResult)
continue;
if (strcmp(szModemName, szTargetName) == 0)
{
*lpdwDeviceID = dwDeviceID;
return (SUCCESS);
}
}
return (LINEERR_OPERATIONFAILED);
}
//
// FUNCTION: void dialFillLocationComboBox(HWND)
//
// PURPOSE: Fills the control with the available calling from locations.
//
// PARAMETERS:
// hwndDlg - handle to the current "Dial" dialog
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
//
void dialFillLocationComboBox(LPDPDIAL globals, HWND hwndDlg, int item, DWORD dwDefaultLocation)
{
LPLINETRANSLATECAPS lpTranslateCaps = NULL;
LPLINELOCATIONENTRY lpLocationEntry;
DWORD dwCounter;
LONG index;
LINERESULT lResult;
// get translate caps
lResult = dialGetTranslateCaps(globals, TAPIVERSION, &lpTranslateCaps);
if LINEERROR(lResult)
return;
// Find the location information in the TRANSLATECAPS
lpLocationEntry = (LPLINELOCATIONENTRY)
(((LPBYTE) lpTranslateCaps) + lpTranslateCaps->dwLocationListOffset);
// First empty the combobox
SendDlgItemMessage(hwndDlg, item, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0);
// enumerate all the locations
for (dwCounter = 0; dwCounter < lpTranslateCaps->dwNumLocations; dwCounter++)
{
// Put each one into the combobox
index = (DWORD)SendDlgItemMessage(hwndDlg, item,
CB_ADDSTRING,
(WPARAM) 0,
(LPARAM) (((LPBYTE) lpTranslateCaps) +
lpLocationEntry[dwCounter].dwLocationNameOffset));
// Is this location the 'current' location?
if (lpLocationEntry[dwCounter].dwPermanentLocationID ==
lpTranslateCaps->dwCurrentLocationID)
{
// Set this to be the active location.
SendDlgItemMessage(hwndDlg, item, CB_SETCURSEL, (WPARAM) index, (LPARAM) 0);
}
}
if (lpTranslateCaps)
GlobalFreePtr(lpTranslateCaps);
}
char gTempStr[200];
LONG lineError(LONG err, LPSTR modName, DWORD lineNum)
{
if (err)
DPF(0, "TAPI line error in %s at line %d : %s", modName, lineNum, GetLineErrStr(err));
return (err);
}
LPSTR GetCallStateStr(DWORD callState)
{
switch (callState)
{
case LINECALLSTATE_IDLE: return ("LINECALLSTATE_IDLE");
case LINECALLSTATE_OFFERING: return ("LINECALLSTATE_OFFERING");
case LINECALLSTATE_ACCEPTED: return ("LINECALLSTATE_ACCEPTED");
case LINECALLSTATE_DIALTONE: return ("LINECALLSTATE_DIALTONE");
case LINECALLSTATE_DIALING: return ("LINECALLSTATE_DIALING");
case LINECALLSTATE_RINGBACK: return ("LINECALLSTATE_RINGBACK");
case LINECALLSTATE_BUSY: return ("LINECALLSTATE_BUSY");
case LINECALLSTATE_SPECIALINFO: return ("LINECALLSTATE_SPECIALINFO");
case LINECALLSTATE_CONNECTED: return ("LINECALLSTATE_CONNECTED");
case LINECALLSTATE_PROCEEDING: return ("LINECALLSTATE_PROCEEDING");
case LINECALLSTATE_ONHOLD: return ("LINECALLSTATE_ONHOLD");
case LINECALLSTATE_CONFERENCED: return ("LINECALLSTATE_CONFERENCED");
case LINECALLSTATE_ONHOLDPENDCONF: return ("LINECALLSTATE_ONHOLDPENDCONF");
case LINECALLSTATE_ONHOLDPENDTRANSFER: return ("LINECALLSTATE_ONHOLDPENDTRANSFER");
case LINECALLSTATE_DISCONNECTED: return ("LINECALLSTATE_DISCONNECTED");
case LINECALLSTATE_UNKNOWN: return ("LINECALLSTATE_UNKNOWN");
}
wsprintf(gTempStr, "UNKNOWN CALL STATE = %lu", callState);
return (gTempStr);
}
LPSTR GetLineMsgStr(DWORD msg)
{
switch (msg)
{
case LINE_ADDRESSSTATE: return ("LINE_ADDRESSSTATE");
case LINE_CALLINFO: return ("LINE_CALLINFO");
case LINE_CALLSTATE: return ("LINE_CALLSTATE");
case LINE_CLOSE: return ("LINE_CLOSE");
case LINE_DEVSPECIFIC: return ("LINE_DEVSPECIFIC");
case LINE_DEVSPECIFICFEATURE: return ("LINE_DEVSPECIFICFEATURE");
case LINE_GATHERDIGITS: return ("LINE_GATHERDIGITS");
case LINE_GENERATE: return ("LINE_GENERATE");
case LINE_LINEDEVSTATE: return ("LINE_LINEDEVSTATE");
case LINE_MONITORDIGITS: return ("LINE_MONITORDIGITS");
case LINE_MONITORMEDIA: return ("LINE_MONITORMEDIA");
case LINE_MONITORTONE: return ("LINE_MONITORTONE");
case LINE_REPLY: return ("LINE_REPLY");
case LINE_REQUEST: return ("LINE_REQUEST");
}
wsprintf(gTempStr, "UNKNOWN LINE MESSAGE = %lu", msg);
return (gTempStr);
}
LPSTR GetLineErrStr(LONG err)
{
switch (err)
{
case LINEERR_ADDRESSBLOCKED: return ("LINEERR_ADDRESSBLOCKED");
case LINEERR_ALLOCATED: return ("LINEERR_ALLOCATED");
case LINEERR_BADDEVICEID: return ("LINEERR_BADDEVICEID");
case LINEERR_BEARERMODEUNAVAIL: return ("LINEERR_BEARERMODEUNAVAIL");
case LINEERR_CALLUNAVAIL: return ("LINEERR_CALLUNAVAIL");
case LINEERR_COMPLETIONOVERRUN: return ("LINEERR_COMPLETIONOVERRUN");
case LINEERR_CONFERENCEFULL: return ("LINEERR_CONFERENCEFULL");
case LINEERR_DIALBILLING: return ("LINEERR_DIALBILLING");
case LINEERR_DIALQUIET: return ("LINEERR_DIALQUIET");
case LINEERR_DIALDIALTONE: return ("LINEERR_DIALDIALTONE");
case LINEERR_DIALPROMPT: return ("LINEERR_DIALPROMPT");
case LINEERR_INCOMPATIBLEAPIVERSION: return ("LINEERR_INCOMPATIBLEAPIVERSION");
case LINEERR_INCOMPATIBLEEXTVERSION: return ("LINEERR_INCOMPATIBLEEXTVERSION");
case LINEERR_INIFILECORRUPT: return ("LINEERR_INIFILECORRUPT");
case LINEERR_INUSE: return ("LINEERR_INUSE");
case LINEERR_INVALADDRESS: return ("LINEERR_INVALADDRESS");
case LINEERR_INVALADDRESSID: return ("LINEERR_INVALADDRESSID");
case LINEERR_INVALADDRESSMODE: return ("LINEERR_INVALADDRESSMODE");
case LINEERR_INVALADDRESSSTATE: return ("LINEERR_INVALADDRESSSTATE");
case LINEERR_INVALAPPHANDLE: return ("LINEERR_INVALAPPHANDLE");
case LINEERR_INVALAPPNAME: return ("LINEERR_INVALAPPNAME");
case LINEERR_INVALBEARERMODE: return ("LINEERR_INVALBEARERMODE");
case LINEERR_INVALCALLCOMPLMODE: return ("LINEERR_INVALCALLCOMPLMODE");
case LINEERR_INVALCALLHANDLE: return ("LINEERR_INVALCALLHANDLE");
case LINEERR_INVALCALLPARAMS: return ("LINEERR_INVALCALLPARAMS");
case LINEERR_INVALCALLPRIVILEGE: return ("LINEERR_INVALCALLPRIVILEGE");
case LINEERR_INVALCALLSELECT: return ("LINEERR_INVALCALLSELECT");
case LINEERR_INVALCALLSTATE: return ("LINEERR_INVALCALLSTATE");
case LINEERR_INVALCALLSTATELIST: return ("LINEERR_INVALCALLSTATELIST");
case LINEERR_INVALCARD: return ("LINEERR_INVALCARD");
case LINEERR_INVALCOMPLETIONID: return ("LINEERR_INVALCOMPLETIONID");
case LINEERR_INVALCONFCALLHANDLE: return ("LINEERR_INVALCONFCALLHANDLE");
case LINEERR_INVALCONSULTCALLHANDLE: return ("LINEERR_INVALCONSULTCALLHANDLE");
case LINEERR_INVALCOUNTRYCODE: return ("LINEERR_INVALCOUNTRYCODE");
case LINEERR_INVALDEVICECLASS: return ("LINEERR_INVALDEVICECLASS");
case LINEERR_INVALDIGITLIST: return ("LINEERR_INVALDIGITLIST");
case LINEERR_INVALDIGITMODE: return ("LINEERR_INVALDIGITMODE");
case LINEERR_INVALDIGITS: return ("LINEERR_INVALDIGITS");
case LINEERR_INVALFEATURE: return ("LINEERR_INVALFEATURE");
case LINEERR_INVALGROUPID: return ("LINEERR_INVALGROUPID");
case LINEERR_INVALLINEHANDLE: return ("LINEERR_INVALLINEHANDLE");
case LINEERR_INVALLINESTATE: return ("LINEERR_INVALLINESTATE");
case LINEERR_INVALLOCATION: return ("LINEERR_INVALLOCATION");
case LINEERR_INVALMEDIALIST: return ("LINEERR_INVALMEDIALIST");
case LINEERR_INVALMEDIAMODE: return ("LINEERR_INVALMEDIAMODE");
case LINEERR_INVALMESSAGEID: return ("LINEERR_INVALMESSAGEID");
case LINEERR_INVALPARAM: return ("LINEERR_INVALPARAM");
case LINEERR_INVALPARKMODE: return ("LINEERR_INVALPARKMODE");
case LINEERR_INVALPOINTER: return ("LINEERR_INVALPOINTER");
case LINEERR_INVALPRIVSELECT: return ("LINEERR_INVALPRIVSELECT");
case LINEERR_INVALRATE: return ("LINEERR_INVALRATE");
case LINEERR_INVALREQUESTMODE: return ("LINEERR_INVALREQUESTMODE");
case LINEERR_INVALTERMINALID: return ("LINEERR_INVALTERMINALID");
case LINEERR_INVALTERMINALMODE: return ("LINEERR_INVALTERMINALMODE");
case LINEERR_INVALTIMEOUT: return ("LINEERR_INVALTIMEOUT");
case LINEERR_INVALTONE: return ("LINEERR_INVALTONE");
case LINEERR_INVALTONELIST: return ("LINEERR_INVALTONELIST");
case LINEERR_INVALTONEMODE: return ("LINEERR_INVALTONEMODE");
case LINEERR_INVALTRANSFERMODE: return ("LINEERR_INVALTRANSFERMODE");
case LINEERR_LINEMAPPERFAILED: return ("LINEERR_LINEMAPPERFAILED");
case LINEERR_NOCONFERENCE: return ("LINEERR_NOCONFERENCE");
case LINEERR_NODEVICE: return ("LINEERR_NODEVICE");
case LINEERR_NODRIVER: return ("LINEERR_NODRIVER");
case LINEERR_NOMEM: return ("LINEERR_NOMEM");
case LINEERR_NOMULTIPLEINSTANCE: return ("LINEERR_NOMULTIPLEINSTANCE");
case LINEERR_NOREQUEST: return ("LINEERR_NOREQUEST");
case LINEERR_NOTOWNER: return ("LINEERR_NOTOWNER");
case LINEERR_NOTREGISTERED: return ("LINEERR_NOTREGISTERED");
case LINEERR_OPERATIONFAILED: return ("LINEERR_OPERATIONFAILED");
case LINEERR_OPERATIONUNAVAIL: return ("LINEERR_OPERATIONUNAVAIL");
case LINEERR_RATEUNAVAIL: return ("LINEERR_RATEUNAVAIL");
case LINEERR_REINIT: return ("LINEERR_REINIT");
case LINEERR_RESOURCEUNAVAIL: return ("LINEERR_RESOURCEUNAVAIL");
case LINEERR_STRUCTURETOOSMALL: return ("LINEERR_STRUCTURETOOSMALL");
case LINEERR_TARGETNOTFOUND: return ("LINEERR_TARGETNOTFOUND");
case LINEERR_TARGETSELF: return ("LINEERR_TARGETSELF");
case LINEERR_UNINITIALIZED: return ("LINEERR_UNINITIALIZED");
case LINEERR_USERUSERINFOTOOBIG: return ("LINEERR_USERUSERINFOTOOBIG");
}
wsprintf(gTempStr, "UNKNOWN LINE ERROR = %ld", err);
return (gTempStr);
}