Leaked source code of windows server 2003
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.
 
 
 
 
 
 

789 lines
21 KiB

/* File: cloopctl.c (created 12/16/93, JKH)
*
* Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 12 $
* $Date: 5/01/02 1:00p $
*/
#include <windows.h>
#pragma hdrstop
#include <time.h>
// #define DEBUGSTR
#include "stdtyp.h"
#include "session.h"
#include "timers.h"
#include "com.h"
#include "mc.h"
#include "cnct.h"
#include "cloop.h"
#include "cloop.hh"
#include "htchar.h"
#include <tdll\assert.h>
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopCreateHandle
*
* DESCRIPTION:
* Creates handle for use of com loop routines. This function assumes that
* the emulator and com handles have already been created and stored in the
* session handle when it is called.
*
* ARGUMENTS:
* hSession -- Session handle
*
* RETURNS:
* A handle to be used in all other CLoop calls or NULL if unsuccessful
*/
HCLOOP CLoopCreateHandle(const HSESSION hSession)
{
ST_CLOOP *pstCLoop = (ST_CLOOP *)0;
unsigned ix;
int fSuccess = TRUE;
pstCLoop = malloc(sizeof(*pstCLoop));
if (!pstCLoop)
fSuccess = FALSE;
else
{
// Initialize structure
memset(pstCLoop, 0, sizeof(ST_CLOOP));
pstCLoop->hSession = hSession;
pstCLoop->hEmu = sessQueryEmuHdl(hSession);
pstCLoop->hCom = sessQueryComHdl(hSession);
pstCLoop->afControl = 0;
pstCLoop->afRcvBlocked = 0;
pstCLoop->afSndBlocked = CLOOP_SB_NODATA;
pstCLoop->nRcvBlkCnt = 0;
pstCLoop->fRcvBlkOverride = FALSE;
pstCLoop->fSuppressDsp = FALSE;
pstCLoop->fDataReceived = FALSE;
pstCLoop->htimerRcvDelay = (HTIMER)0;
pstCLoop->pfRcvDelay = CLoopRcvDelayProc;
pstCLoop->pfCharDelay = CLoopCharDelayProc;
pstCLoop->pstFirstOutBlock = NULL;
pstCLoop->pstLastOutBlock = NULL;
pstCLoop->ulOutCount = 0L;
pstCLoop->hOutFile = (HANDLE)0;
pstCLoop->keyLastKey = (KEY_T)0;
pstCLoop->keyHoldKey = (KEY_T)0;
pstCLoop->pstRmtChain = NULL;
pstCLoop->pstRmtChainNext = NULL;
pstCLoop->fRmtChain = FALSE;
pstCLoop->fTextDisplay = FALSE;
pstCLoop->hDisplayBlock = (HANDLE)0;
// Set default user settings
CLoopInitHdl((HCLOOP)pstCLoop);
pstCLoop->lpLearn = (LPVOID)0;
for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
pstCLoop->ahEvents[ix] = (HANDLE)0;
pstCLoop->hEngineThread = (HANDLE)0;
pstCLoop->fDoMBCS = FALSE;
pstCLoop->cLeadByte = 0;
pstCLoop->cLocalEchoLeadByte= 0;
#if defined(CHAR_MIXED)
// Added for debugging
pstCLoop->fDoMBCS = TRUE;
#endif
// Create synchronization objects
InitializeCriticalSection(&pstCLoop->csect);
}
if (!fSuccess)
CLoopDestroyHandle((HCLOOP *)&pstCLoop);
DBGOUT_NORMAL("CLoopCreateHandle(%lX) returned %lX\r\n",
hSession, pstCLoop, 0, 0, 0);
return (HCLOOP)pstCLoop;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopDestroyHandle
*
* DESCRIPTION:
* Destroys a handle created by CLoopCreateHandle and sets the storage
* variable to NULL;
*
* ARGUMENTS:
* ppstCLoop -- address of a variable holding a CLoop Handle
*
* RETURNS:
* nothing
*/
void CLoopDestroyHandle(HCLOOP * const ppstCLoop)
{
ST_CLOOP *pstCLoop;
assert(ppstCLoop);
pstCLoop = (ST_CLOOP *)*ppstCLoop;
if (pstCLoop)
{
CLoopDeactivate((HCLOOP)pstCLoop);
DeleteCriticalSection(&pstCLoop->csect);
free(pstCLoop);
pstCLoop = NULL;
}
*ppstCLoop = (HCLOOP)0;
DBGOUT_NORMAL("CLoopDestroyHandle(l%X)\r\n", pstCLoop, 0,0,0,0);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* CLoopActivate
*
* DESCRIPTION:
* Prepares cloop handle for actual use by starting its thread.
*
* ARGUMENTS:
* pstCLoop -- CLoop handle returned from CLoopCreateHandle
*
* RETURNS:
* TRUE if thread was started, FALSE otherwise
*/
int CLoopActivate(const HCLOOP hCLoop)
{
int fSuccess = TRUE;
ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
unsigned ix;
DWORD dwThreadId;
// Store these in handle for fast access
pstCLoop->hEmu = sessQueryEmuHdl(pstCLoop->hSession);
pstCLoop->hCom = sessQueryComHdl(pstCLoop->hSession);
for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
{
pstCLoop->ahEvents[ix] = CreateEvent(NULL,
TRUE, // must be manually reset
FALSE, // create unsignalled
NULL); // unnamed
if (pstCLoop->ahEvents[ix] == NULL)
{
fSuccess = FALSE;
//
// Make sure to initialize the rest of the event handles to NULL;
//
for (++ix; ix < DIM(pstCLoop->ahEvents); ++ix)
{
pstCLoop->ahEvents[ix] = NULL;
}
}
}
if (fSuccess)
{
// Start the thread to handle cloop's responsibilities
// (Gentleprograms, start your engines
EnterCriticalSection(&pstCLoop->csect);
pstCLoop->hEngineThread = CreateThread(
(LPSECURITY_ATTRIBUTES)0,
4096,
(LPTHREAD_START_ROUTINE)CLoop,
(LPVOID)pstCLoop,
0,
&dwThreadId);
if (!pstCLoop->hEngineThread)
fSuccess = FALSE;
#if 0 //jmh 07-10-96
else
SetThreadPriority(pstCLoop->hEngineThread,
THREAD_PRIORITY_HIGHEST);
#endif // 0
LeaveCriticalSection(&pstCLoop->csect);
}
return fSuccess;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* CLoopDeactivate
*
* DESCRIPTION:
* Shuts down cloop but does not destroy the handle
*
* ARGUMENTS:
* pstCLoop -- CLoop handle returned from CLoopCreateHandle
*
* RETURNS:
* nothing
*/
void CLoopDeactivate(const HCLOOP hCLoop)
{
ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
unsigned ix;
if (pstCLoop)
{
// This next call should cause the cloop thread to exit
// Don't enter critical section to do this, since thread won't
// be able to exit
if (pstCLoop->hEngineThread)
{
//JMH 05-28-96 CLoop was blowing up when no phone number was
// provided, and you exited, answering no to the save prompt.
// Suspending receive before terminating the thread fixed it.
//
CLoopRcvControl((HCLOOP)pstCLoop, CLOOP_SUSPEND, CLOOP_RB_INACTIVE);
CLoopControl((HCLOOP)pstCLoop, CLOOP_SET, CLOOP_TERMINATE);
// Wait for the engine thread to exit
if (WaitForSingleObject(pstCLoop->hEngineThread, 0) == WAIT_OBJECT_0)
{
CloseHandle(pstCLoop->hEngineThread);
}
else if (WaitForSingleObject(pstCLoop->hEngineThread, 10000) == WAIT_TIMEOUT)
{
TerminateThread(pstCLoop->hEngineThread, 0);
CloseHandle(pstCLoop->hEngineThread);
}
pstCLoop->hEngineThread = (HANDLE)0;
}
for (ix = 0; ix < DIM(pstCLoop->ahEvents); ++ix)
{
if (pstCLoop->ahEvents[ix])
{
CloseHandle(pstCLoop->ahEvents[ix]);
pstCLoop->ahEvents[ix] = INVALID_HANDLE_VALUE;
}
}
}
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopReset
*
* DESCRIPTION:
* Initializes the cloop routines for a new call. This is not really
* necessary prior to the first connection, but prevents left-over flags,
* buffers and such from one connection from affecting later connections.
*
* ARGUMENTS:
* pstCLoop -- CLoop handle returned from CLoopCreateHandle
*
* RETURNS:
* nothing
*/
void CLoopReset(const HCLOOP hCLoop)
{
ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
pstCLoop->afControl = 0;
pstCLoop->afRcvBlocked = 0;
pstCLoop->afSndBlocked = CLOOP_SB_NODATA;
CLoopClearOutput((HCLOOP)pstCLoop);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopRcvControl
*
* DESCRIPTION:
* Used to suspend and resume receiving in the CLoop routines. Can be
* called from Client or Wudge. Requests can be made to suspend or resume
* receiving for any of several reasons. Receiving can be suspended for
* more than one reason at a time. It will not resume until all reasons
* have been cleared.
*
* ARGUMENTS:
* hCLoop -- CLoop handle returned from CLoopCreateHandle
* iAction -- One of CLOOP_SUSPEND or CLOOP_RESUME
* iReason -- Reason for action as defined in cloop.h
* Ex.: CLOOP_RB_NODATA, CLOOP_RB_INACTIVE
* CLOOP_RB_SCRLOCK, CLOOP_RB_SCRIPT
*
* RETURNS:
* nothing
*/
void CLoopRcvControl(const HCLOOP hCLoop,
const unsigned uAction,
const unsigned uReason)
{
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
assert(uAction == CLOOP_SUSPEND || uAction == CLOOP_RESUME);
EnterCriticalSection(&pstCLoop->csect);
if (uReason == CLOOP_RB_SCRIPT)
{
/*
* Scripts work a little bit different
*/
// DbgOutStr("CLOOP_RB_SCRIPT %d", pstCLoop->nRcvBlkCnt, 0,0,0,0);
switch (uAction)
{
default:
break;
case CLOOP_SUSPEND:
pstCLoop->nRcvBlkCnt += 1;
break;
case CLOOP_RESUME:
pstCLoop->nRcvBlkCnt -= 1;
// There used to be code to prevent this value from going neg.
// but we must allow this to go negative so that cleanup
// can occur when we abort within an API call.
break;
}
// DbgOutStr(" %d\r\n", pstCLoop->nRcvBlkCnt, 0,0,0,0);
if (pstCLoop->fRcvBlkOverride == FALSE)
{
/*
* If someone is overriding us, let them restore the bits
*/
if (pstCLoop->nRcvBlkCnt > 0)
{
bitset(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
}
else
{
bitclear(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
}
}
}
else
{
if (uAction == CLOOP_SUSPEND)
bitset(pstCLoop->afRcvBlocked, uReason);
else if (uAction == CLOOP_RESUME)
bitclear(pstCLoop->afRcvBlocked, uReason);
}
DBGOUT_NORMAL("CLoopRcvControl(%08lx):%04X (fRcvBlkOverride=%d, nRcvBlkCnt=%d)\r\n",
pstCLoop, pstCLoop->afRcvBlocked, pstCLoop->fRcvBlkOverride,
pstCLoop->nRcvBlkCnt,0);
if (pstCLoop->afRcvBlocked)
ResetEvent(pstCLoop->ahEvents[EVENT_RCV]);
else
SetEvent(pstCLoop->ahEvents[EVENT_RCV]);
LeaveCriticalSection(&pstCLoop->csect);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopOverrideControl
*
* DESCRIPTION:
* This function can be called internally from the engine in order to
* override the CLoopRcvControl \CLOOP_RB_SCRIPT blocking state. It is
* intended to be used during a connection process, when the connection
* stuff needs to see the data coming in.
*
* ARGUEMENTS:
* hCLoop -- CLoop handle returned from CLoopCreateHandle
* fOverride -- TRUE to override, FALSE to restore things
*
* RETURNS:
* Nothing.
*/
void CLoopOverrideControl(const HCLOOP hCLoop, const int fOverride)
{
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
EnterCriticalSection(&pstCLoop->csect);
if (fOverride)
{
pstCLoop->fRcvBlkOverride = TRUE;
if (pstCLoop->nRcvBlkCnt > 0)
{
bitclear(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
if (!pstCLoop->afRcvBlocked)
SetEvent(pstCLoop->ahEvents[EVENT_RCV]);
}
}
else
{
pstCLoop->fRcvBlkOverride = FALSE;
if (pstCLoop->nRcvBlkCnt > 0)
{
bitset(pstCLoop->afRcvBlocked, CLOOP_RB_SCRIPT);
ResetEvent(pstCLoop->ahEvents[EVENT_RCV]);
}
}
LeaveCriticalSection(&pstCLoop->csect);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopSndControl
*
* DESCRIPTION:
* Used to suspend and resume sending from the CLoop routines.
* Requests can be made to suspend or resume sending for any of several
* reasons. Sending can be suspended for more than one reason at a time.
* It will not resume until all reasons have been cleared.
*
* ARGUMENTS:
* hCLoop -- CLoop handle returned from CLoopCreateHandle
* uAction -- One of CLOOP_SUSPEND or CLOOP_RESUME
* uReason -- Reason for action as defined in cloop.h
* Ex.: CLOOP_SB_NODATA, CLOOP_SB_INACTIVE
* CLOOP_SB_SCRLOCK, CLOOP_SB_LINEWAIT
*
* RETURNS:
* nothing
*/
void CLoopSndControl(const HCLOOP hCLoop,
const unsigned uAction,
const unsigned uReason)
{
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
assert(uAction == CLOOP_SUSPEND || uAction == CLOOP_RESUME);
DbgOutStr("CLoopSndControl(%x, %x)\r\n", uAction, uReason, 0,0,0);
EnterCriticalSection(&pstCLoop->csect);
if (uAction == CLOOP_SUSPEND)
{
if (!pstCLoop->afSndBlocked)
{
DbgOutStr("Resetting EVENT_SEND (0x%x)\r\n", 0,0,0,0,0);
ResetEvent(pstCLoop->ahEvents[EVENT_SEND]);
}
bitset(pstCLoop->afSndBlocked, uReason);
}
else if (uAction == CLOOP_RESUME)
{
// Allow this bit to be reset
//
if (bittest(uReason, CLOOP_SB_CNCTDRV))
bitclear(pstCLoop->afSndBlocked, CLOOP_SB_CNCTDRV);
// Only do this if we're not in the process of connecting
//
if (! bittest(pstCLoop->afSndBlocked, CLOOP_SB_CNCTDRV))
{
bitclear(pstCLoop->afSndBlocked, uReason);
// If sending is being resumed because new data has arrived,
// make sure we're connected. If not, send off a message to
// try to connect without dialing
if (bittest(uReason, CLOOP_SB_NODATA))
{
if (cnctQueryStatus(sessQueryCnctHdl(pstCLoop->hSession)) ==
CNCT_STATUS_FALSE)
{
bitset(pstCLoop->afSndBlocked, CLOOP_SB_UNCONNECTED);
}
if (bittest(pstCLoop->afSndBlocked, CLOOP_SB_UNCONNECTED))
{
NotifyClient(pstCLoop->hSession, (int) EVENT_PORTONLY_OPEN, 0);
}
}
}
if (!pstCLoop->afSndBlocked)
{
DbgOutStr("Setting EVENT_SEND\r\n", 0,0,0,0,0);
SetEvent(pstCLoop->ahEvents[EVENT_SEND]);
}
}
LeaveCriticalSection(&pstCLoop->csect);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopControl
*
* DESCRIPTION:
* Used to control the action of the CLoop engine.
* The CLoop engine normally processes any characters
* received from the remote system and any characters or keys queued for
* output. This call can be used to alter the normal flow of data for
* special needs such as file transfers and scripts.
*
* ARGUMENTS:
* hCLoop -- Handle returned from call to CLoopCreateHandle
* uAction -- CLOOP_SET or CLOOP_CLEAR to set or clear control bits
* uReason -- Value indicating what is being controlled. Values are
* listed in cloop.h
* Ex:CLOOP_TERMINATE CLOOP_OUTPUT_WAITING CLOOP_TRANSFER_READY
*
* RETURNS:
* nothing
*/
void CLoopControl(
const HCLOOP hCLoop,
unsigned uAction,
unsigned uReason)
{
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
if ( !pstCLoop )
return; //MPT:10SEP98 to prevent an access violation
EnterCriticalSection(&pstCLoop->csect);
if (bittest(uReason, CLOOP_MBCS))
{
if (uAction == CLOOP_SET)
pstCLoop->fDoMBCS = TRUE;
else
pstCLoop->fDoMBCS = FALSE;
bitclear(uReason, CLOOP_MBCS);
// I am not sure about returning here or not ...
// As is, it requires that this be the only flag used for this call.
LeaveCriticalSection(&pstCLoop->csect);
return;
}
assert(uAction == CLOOP_SET || uAction == CLOOP_CLEAR);
if (bittest(uReason, CLOOP_CONNECTED))
{
if (uAction == CLOOP_SET)
{
CLoopSndControl(hCLoop, CLOOP_RESUME, CLOOP_SB_UNCONNECTED);
}
else
{
CLoopClearOutput(hCLoop);
CLoopSndControl(hCLoop, CLOOP_SUSPEND, CLOOP_SB_NODATA);
}
// Don't put this flag in afControl
bitclear(uReason, CLOOP_CONNECTED);
}
if (bittest(uReason, CLOOP_SUPPRESS_DSP))
{
// This bit cannot be kept in afControl because doing so would
// keep cloop from suspending itself when appropriate
pstCLoop->fSuppressDsp = (uAction == CLOOP_SET);
bitclear(uAction, CLOOP_SUPPRESS_DSP);
}
#if 0
if (uAction == CLOOP_SET)
{
bitset(pstCLoop->afControl, uReason);
SetEvent(pstCLoop->ahEvents[EVENT_SEND]);
}
else if (uAction == CLOOP_CLEAR)
{
bitclear(pstCLoop->afControl, uReason);
if (!pstCLoop->afControl)
ResetEvent(pstCLoop->ahEvents[EVENT_SEND]);
}
#endif
if (bittest(uReason, CLOOP_MBCS))
{
if (uAction == CLOOP_SET)
pstCLoop->fDoMBCS = TRUE;
else
pstCLoop->fDoMBCS = FALSE;
bitclear(uReason, CLOOP_MBCS);
// I am not sure about returning here or not ...
LeaveCriticalSection(&pstCLoop->csect);
return;
}
if (uAction == CLOOP_SET)
bitset(pstCLoop->afControl, uReason);
else if (uAction == CLOOP_CLEAR)
bitclear(pstCLoop->afControl, uReason);
if (pstCLoop->afControl)
SetEvent(pstCLoop->ahEvents[EVENT_CONTROL]);
else
ResetEvent(pstCLoop->ahEvents[EVENT_CONTROL]);
LeaveCriticalSection(&pstCLoop->csect);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopRegisterRmtInputChain
*
* DESCRIPTION:
* Adds a function to a chain of functions that are called whenever
* a new character is received from the remote system.
*
* ARGUMENTS:
* pstCLoop -- Value returned from CLoopCreateHandle
* pfFunc -- Pointer to a function to be called when each remote
* character is received. The function should be declared as:
* VOID FAR PASCAL FunctionName(METACHAR mc, VOID FAR *pvUserData)
* The value passed in the argument should be the return value
* from MakeProcInstance.
* pvUserData -- Any arbitrary value that can be cast to VOID FAR *. This
* value will be maintained in the chain and passed back to
* the caller whenever (l*pfFunc) is called. No use is made
* of this value by the CLoop routines.
*
* RETURNS:
* A void * return handle that must be saved and passed to
* CLoopUnregisterRmtInputChain when the function is no longer needed.
*/
void * CLoopRegisterRmtInputChain(const HCLOOP hCLoop,
const CHAINFUNC pfFunc,
void *pvUserData)
{
ST_CLOOP * const pstCLoop = (ST_CLOOP *)hCLoop;
ST_FCHAIN *pstNew = NULL;
assert(pfFunc);
assert(pstCLoop);
if ((pstNew = (ST_FCHAIN *)malloc(sizeof(*pstNew))) != NULL)
{
EnterCriticalSection(&pstCLoop->csect);
// Initialize new node
pstNew->pstParent = pstCLoop;
pstNew->pfFunc = pfFunc;
pstNew->pvUserData = pvUserData;
DBGOUT_NORMAL("CLoopRegisterRmtInputChain(0x%lx, 0x%lx) -> %lX\r\n",
(LONG)pstNew->pfFunc, (LONG)pstNew->pvUserData,
pstNew, 0, 0);
// Always link new functions into beginning of chain. That way, if
// a new function is added into the chain from within a current
// callback, it will not be called until the next char. arrives.
pstNew->pstNext = pstCLoop->pstRmtChain;
pstCLoop->pstRmtChain = pstNew;
pstNew->pstPrior = NULL;
pstCLoop->fRmtChain = TRUE;
LeaveCriticalSection(&pstCLoop->csect);
}
return (void *)pstNew;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: CLoopUnregisterRmtInputChain
*
* DESCRIPTION:
* Removes a function from the chain of functions called when a remote
* character is received.
*
* ARGUMENTS:
* pvHdl -- Value returned from an earlier call to CLoopRegisterRmtInputChain
*
* RETURNS:
* nothing
*/
void CLoopUnregisterRmtInputChain(void *pvHdl)
{
ST_FCHAIN *pstNode = (ST_FCHAIN *)pvHdl;
ST_CLOOP *pstCLoop;
assert(pstNode);
pstCLoop = pstNode->pstParent;
EnterCriticalSection(&pstCLoop->csect);
// See if we are removing next scheduled chain function
if (pstNode == pstCLoop->pstRmtChainNext)
{
pstCLoop->pstRmtChainNext = pstNode->pstNext;
}
// Unlink node
if (pstNode->pstPrior)
{
pstNode->pstPrior->pstNext = pstNode->pstNext;
}
else
{
pstCLoop->pstRmtChain = pstNode->pstNext;
if (!pstNode->pstNext)
{
pstCLoop->fRmtChain = FALSE;
}
}
if (pstNode->pstNext)
{
pstNode->pstNext->pstPrior = pstNode->pstPrior;
}
DBGOUT_NORMAL("CLoopUnregisterRmtInputChain(0x%lx)\r\n",
(LONG)pvHdl, 0, 0, 0, 0);
free(pstNode);
pstNode = NULL;
LeaveCriticalSection(&pstCLoop->csect);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: QueryCLoopMBCSState
*
* DESCRIPTION: Determines the current DBCS mode.
*
* ARGUMENTS:
* hCLoop -- Handle returned from call to CLoopCreateHandle
*
* RETURNS:
* TRUE - if we are in DBCS mode.
* FALSE - if we're not
*/
int QueryCLoopMBCSState(HCLOOP hCLoop)
{
ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
assert(pstCLoop);
return(pstCLoop->fDoMBCS);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: SetCLoopMBCSState
*
* DESCRIPTION: Turns on/off DBCS mode.
*
* ARGUMENTS:
* hCLoop -- Handle returned from call to CLoopCreateHandle
* fState -- TRUE, if we're turning MBCS on,
* FALSE, if we're turning MBCS off.
*
* RETURNS:
* the value of dDoMBCS from the CLoop's internal struct
*/
int SetCLoopMBCSState(HCLOOP hCLoop, int fState)
{
ST_CLOOP *pstCLoop = (ST_CLOOP *)hCLoop;
assert(pstCLoop);
pstCLoop->fDoMBCS = fState;
return(pstCLoop->fDoMBCS);
}