📄 win32_modem.cpp
字号:
//
// FUNCTION: long WaitForReply(long)
//
// PURPOSE: Resynchronize by waiting for a LINE_REPLY
//
// PARAMETERS:
// lRequestID - The asynchronous request ID that we're
// on a LINE_REPLY for.
//
// RETURN VALUE:
// - 0 if LINE_REPLY responded with a success.
// - LINEERR constant if LINE_REPLY responded with a LINEERR
// - 1 if the line was shut down before LINE_REPLY is received.
//
// COMMENTS:
//
// This function allows us to resynchronize an asynchronous
// TAPI line call by waiting for the LINE_REPLY message. It
// waits until a LINE_REPLY is received or the line is shut down.
//
// Note that this could cause re-entrancy problems as
// well as mess with any message preprocessing that might
// occur on this thread (such as TranslateAccelerator).
//
// This function should to be called from the thread that did
// lineInitialize, or the PeekMessage is on the wrong thread
// and the synchronization is not guaranteed to work. Also note
// that if another PeekMessage loop is entered while waiting,
// this could also cause synchronization problems.
//
// One more note. This function can potentially be re-entered
// if the call is dropped for any reason while waiting. If this
// happens, just drop out and assume the wait has been canceled.
// This is signaled by setting bReentered to FALSE when the function
// is entered and TRUE when it is left. If bReentered is ever TRUE
// during the function, then the function was re-entered.
//
// This function times out and returns WAITERR_WAITTIMEDOUT
// after WAITTIMEOUT milliseconds have elapsed.
//
//
long Win32_Modem::WaitForReply (long lRequestID)
{
static bool bReentered;
bReentered = FALSE;
if (lRequestID > SUCCESS)
{
MSG msg;
DWORD dwTimeStarted;
g_bReplyRecieved = FALSE;
g_dwRequestedID = (DWORD) lRequestID;
// Initializing this just in case there is a bug
// that sets g_bReplyRecieved without setting the reply value.
g_lAsyncReply = LINEERR_OPERATIONFAILED;
dwTimeStarted = GetTickCount();
while(!g_bReplyRecieved)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// This should only occur if the line is shut down while waiting.
if (!g_bTapiInUse || bReentered)
{
bReentered = TRUE;
return WAITERR_WAITABORTED;
}
// Its a really bad idea to timeout a wait for a LINE_REPLY.
// If we are execting a LINE_REPLY, we should wait till we get
// it; it might take a long time to dial (for example).
// If 5 seconds go by without a reply, it might be a good idea
// to display a dialog box to tell the user that a
// wait is in progress and to give the user the capability to
// abort the wait.
}
bReentered = TRUE;
return g_lAsyncReply;
}
bReentered = TRUE;
return lRequestID;
}
//
// FUNCTION: long WaitForCallState(DWORD)
//
// PURPOSE: Wait for the line to reach a specific CallState.
//
// PARAMETERS:
// dwDesiredCallState - specific CallState to wait for.
//
// RETURN VALUE:
// Returns 0 (SUCCESS) when we reach the Desired CallState.
// Returns WAITERR_WAITTIMEDOUT if timed out.
// Returns WAITERR_WAITABORTED if call was closed while waiting.
//
// COMMENTS:
//
// This function allows us to synchronously wait for a line
// to reach a specific LINESTATE or until the line is shut down.
//
// Note that this could cause re-entrancy problems as
// well as mess with any message preprocessing that might
// occur on this thread (such as TranslateAccelerator).
//
// One more note. This function can potentially be re-entered
// if the call is dropped for any reason while waiting. If this
// happens, just drop out and assume the wait has been canceled.
// This is signaled by setting bReentered to FALSE when the function
// is entered and TRUE when it is left. If bReentered is ever TRUE
// during the function, then the function was re-entered.
//
// This function should to be called from the thread that did
// lineInitialize, or the PeekMessage is on the wrong thread
// and the synchronization is not guaranteed to work. Also note
// that if another PeekMessage loop is entered while waiting,
// this could also cause synchronization problems.
//
// If the constant value I_LINECALLSTATE_ANY is used for the
// dwDesiredCallState, then WaitForCallState will return SUCCESS
// upon receiving any CALLSTATE messages.
//
//
//
long Win32_Modem::WaitForCallState(DWORD dwDesiredCallState)
{
MSG msg;
DWORD dwTimeStarted;
static bool bReentered;
bReentered = FALSE;
dwTimeStarted = GetTickCount();
g_bCallStateReceived = FALSE;
while ((dwDesiredCallState == I_LINECALLSTATE_ANY) ||
(g_dwCallState != dwDesiredCallState))
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// If we are waiting for any call state and get one, succeed.
if ((dwDesiredCallState == I_LINECALLSTATE_ANY) &&
g_bCallStateReceived)
{
//OutputDebugString("Any call state achieved");
bReentered = TRUE;
return SUCCESS;
}
// This should only occur if the line is shut down while waiting.
else if (/*!g_bTapiInUse || */bReentered)
{
bReentered = TRUE;
//OutputDebugString("WAITABORTED\n");
return WAITERR_WAITABORTED;
}
// If we don't get the reply in a reasonable time, we time out.
// if (GetTickCount() - dwTimeStarted > WAITTIMEOUT)
else if ((GetTickCount() - dwTimeStarted) > 3000)
{
bReentered = TRUE;
//OutputDebugString("WAITTIMEDOUT\n");
return WAITERR_WAITTIMEDOUT;
}
}
//OutputDebugString("Desired call state achieved");
bReentered = TRUE;
return SUCCESS;
}
//**************************************************
// lineCallback Function and Handlers.
//**************************************************
//
// FUNCTION: lineCallbackFunc(..)
//
// PURPOSE: Receive asynchronous TAPI events
//
// PARAMETERS:
// dwDevice - Device associated with the event, if any
// dwMsg - TAPI event that occurred.
// dwCallbackInstance - User defined data supplied when opening the line.
// dwParam1 - dwMsg specific information
// dwParam2 - dwMsg specific information
// dwParam3 - dwMsg specific information
//
// RETURN VALUE:
// none
//
// COMMENTS:
// This is the function where all asynchronous events will come.
// Almost all events will be specific to an open line, but a few
// will be general TAPI events (such as LINE_REINIT).
//
// Its important to note that this callback will *ALWAYS* be
// called in the context of the thread that does the lineInitialize.
// Even if another thread (such as the COMM threads) calls the API
// that would result in the callback being called, it will be called
// in the context of the main thread (since in this sample, the main
// thread does the lineInitialize).
//
//
void CALLBACK Win32_Modem::lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
// OutputDebugLineCallback(
// dwDevice, dwMsg, dwCallbackInstance,
// dwParam1, dwParam2, dwParam3);
// All we do is dispatch the dwMsg to the correct handler.
switch(dwMsg)
{
case LINE_CALLSTATE:
//OutputDebugString("Linecallstate");
DoLineCallState(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_CLOSE:
//OutputDebugString("Lineclose");
DoLineClose(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_LINEDEVSTATE:
//OutputDebugString("Linedevstate");
DoLineDevState(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_REPLY:
//OutputDebugString("Linereply");
DoLineReply(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_CREATE:
//OutputDebugString("Linecreate");
DoLineCreate(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
default:
//OutputDebugString("lineCallbackFunc message ignored\n");
break;
}
return;
}
//
// FUNCTION: DoLineReply(..)
//
// PURPOSE: Handle LINE_REPLY asynchronous messages.
//
// PARAMETERS:
// dwDevice - Line Handle associated with this LINE_REPLY.
// dwMsg - Should always be LINE_REPLY.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - Asynchronous request ID.
// dwParam2 - success or LINEERR error value.
// dwParam3 - Unused.
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
// All line API calls that return an asynchronous request ID
// will eventually cause a LINE_REPLY message. Handle it.
//
// This sample assumes only one call at time, and that we wait
// for a LINE_REPLY before making any other line API calls.
//
// The only exception to the above is that we might shut down
// the line before receiving a LINE_REPLY.
//
//
void Win32_Modem::DoLineReply(
DWORD dwDevice, DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
/* if ((long) dwParam2 != SUCCESS)
OutputDebugLineError((long) dwParam2, "LINE_REPLY error: ");
else
OutputDebugString("LINE_REPLY: successfully replied.\n");
*/
// If we are currently waiting for this async Request ID
// then set the global variables to acknowledge it.
if (g_dwRequestedID == dwParam1)
{
g_bReplyRecieved = TRUE;
g_lAsyncReply = (long) dwParam2;
}
}
//
// FUNCTION: DoLineClose(..)
//
// PURPOSE: Handle LINE_CLOSE asynchronous messages.
//
// PARAMETERS:
// dwDevice - Line Handle that was closed.
// dwMsg - Should always be LINE_CLOSE.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - Unused.
// dwParam2 - Unused.
// dwParam3 - Unused.
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
// This message is sent when something outside our app shuts
// down a line in use.
//
// The hLine (and any hCall on this line) are no longer valid.
//
//
void Win32_Modem::DoLineClose(
DWORD dwDevice, DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
// Line has been shut down. Clean up our internal variables.
g_hLine = NULL;
g_hCall = NULL;
HangupCall();
}
//
// FUNCTION: DoLineDevState(..)
//
// PURPOSE: Handle LINE_LINEDEVSTATE asynchronous messages.
//
// PARAMETERS:
// dwDevice - Line Handle that was closed.
// dwMsg - Should always be LINE_LINEDEVSTATE.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - LINEDEVSTATE constant.
// dwParam2 - Depends on dwParam1.
// dwParam3 - Depends on dwParam1.
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
// The LINE_LINEDEVSTATE message is received if the state of the line
// changes. Examples are RINGING, MAINTENANCE, MSGWAITON. Very few of
// these are relevant to this sample.
//
// Assuming that any LINEDEVSTATE that removes the line from use by TAPI
// will also send a LINE_CLOSE message.
//
//
void Win32_Modem::DoLineDevState(
DWORD dwDevice, DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
switch(dwParam1)
{
case LINEDEVSTATE_RINGING:
// UpdateStatusBar("Line Ringing",1,0);
//OutputDebugString("Line Ringing.\n");
break;
case LINEDEVSTATE_REINIT:
// This is an important case! Usually means that a service provider
// has changed in such a way that requires TAPI to REINIT.
// Note that there are both 'soft' REINITs and 'hard' REINITs.
// Soft REINITs don't actually require a full shutdown but is instead
// just an informational change that historically required a REINIT
// to force the application to deal with. TAPI API Version 1.3 apps
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -