Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

5859 lines
139 KiB

/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 1995-1996 Microsoft Corporation
Module Name:
server.c
Abstract:
Src module for tapi server
Author:
Dan Knudson (DanKn) 01-Apr-1995
Revision History:
--*/
#define MYTEST 1
#include "windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "process.h"
#include "tapi.h"
#include "tspi.h"
#include "..\client\client.h"
#include "server.h"
#include "private.h"
#include "tapsrv.h"
#include "..\perfdll\tapiperf.h"
// PERF
PERFBLOCK PerfBlock;
BOOL InitPerf();
HANDLE ghToken;
TAPIGLOBALS TapiGlobals;
BOOL gbPriorityListsInitialized = FALSE;
BOOL gbQueueSPEvents = FALSE;
CRITICAL_SECTION gSafeMutexCritSec,
gRemoteCliEventBufCritSec,
gRequestIDCritSec,
gPriorityListCritSec,
gSPEventQueueCritSec;
PSPEVENT gpOldestSPEvent = NULL, gpYoungestSPEvent = NULL;
HANDLE ghPendingSPEventsEvent;
#define MIN_WAIT_HINT 60000
DWORD gdwServiceState = SERVICE_START_PENDING,
gdwWaitHint = MIN_WAIT_HINT,
gdwCheckPoint = 0;
#if DBG
//TCHAR gszDebugKey[] = "Software\\Microsoft\\Windows\\" \
// "CurrentVersion\\Telephony\\Debug";
char gszTapiSrvDebugLevel[] = "TapiSrvDebugLevel";
#endif
char gszProvider[] = "Provider";
char gszNumLines[] = "NumLines";
char gszUIDllName[] = "UIDllName";
char gszNumPhones[] = "NumPhones";
char gszSyncLevel[] = "SyncLevel";
char gszProviders[] = "Providers";
WCHAR gszProviderIDW[] = L"ProviderID";
//char gszTelephonIni[] = "telephon.ini";
char gszNumProviders[] = "NumProviders";
char gszNextProviderID[] = "NextProviderID";
WCHAR gszRequestMakeCallW[] = L"RequestMakeCall";
WCHAR gszRequestMediaCallW[] = L"RequestMediaCall";
WCHAR gszProviderFilenameW[] = L"ProviderFilename";
char gszRegKeyHandoffPriorities[] = "Software\\Microsoft\\Windows\\" \
"CurrentVersion\\Telephony\\HandoffPriorities";
char gszRegKeyTelephony[] = "Software\\Microsoft\\Windows\\" \
"CurrentVersion\\Telephony";
char gszRegKeyProviders[] = "Software\\Microsoft\\Windows\\" \
"CurrentVersion\\Telephony\\Providers";
WCHAR *gaszMediaModes[] =
{
L"",
L"unknown",
L"interactivevoice",
L"automatedvoice",
L"datamodem",
L"g3fax",
L"tdd",
L"g4fax",
L"digitaldata",
L"teletex",
L"videotex",
L"telex",
L"mixed",
L"adsi",
L"voiceview",
NULL
};
char *gaszTSPIFuncNames[] =
{
"TSPI_lineAccept",
"TSPI_lineAddToConference",
"TSPI_lineAgentSpecific",
"TSPI_lineAnswer",
"TSPI_lineBlindTransfer",
"TSPI_lineClose",
"TSPI_lineCloseCall",
"TSPI_lineCompleteCall",
"TSPI_lineCompleteTransfer",
"TSPI_lineConditionalMediaDetection",
"TSPI_lineDevSpecific",
"TSPI_lineDevSpecificFeature",
"TSPI_lineDial",
"TSPI_lineDrop",
"TSPI_lineForward",
"TSPI_lineGatherDigits",
"TSPI_lineGenerateDigits",
"TSPI_lineGenerateTone",
"TSPI_lineGetAddressCaps",
"TSPI_lineGetAddressID",
"TSPI_lineGetAddressStatus",
"TSPI_lineGetAgentActivityList",
"TSPI_lineGetAgentCaps",
"TSPI_lineGetAgentGroupList",
"TSPI_lineGetAgentStatus",
"TSPI_lineGetCallAddressID",
"TSPI_lineGetCallInfo",
"TSPI_lineGetCallStatus",
"TSPI_lineGetDevCaps",
"TSPI_lineGetDevConfig",
"TSPI_lineGetExtensionID",
"TSPI_lineGetIcon",
"TSPI_lineGetID",
"TSPI_lineGetLineDevStatus",
"TSPI_lineGetNumAddressIDs",
"TSPI_lineHold",
"TSPI_lineMakeCall",
"TSPI_lineMonitorDigits",
"TSPI_lineMonitorMedia",
"TSPI_lineMonitorTones",
"TSPI_lineNegotiateExtVersion",
"TSPI_lineNegotiateTSPIVersion",
"TSPI_lineOpen",
"TSPI_linePark",
"TSPI_linePickup",
"TSPI_linePrepareAddToConference",
"TSPI_lineRedirect",
"TSPI_lineReleaseUserUserInfo",
"TSPI_lineRemoveFromConference",
"TSPI_lineSecureCall",
"TSPI_lineSelectExtVersion",
"TSPI_lineSendUserUserInfo",
"TSPI_lineSetAgentActivity",
"TSPI_lineSetAgentGroup",
"TSPI_lineSetAgentState",
"TSPI_lineSetAppSpecific",
"TSPI_lineSetCallData",
"TSPI_lineSetCallParams",
"TSPI_lineSetCallQualityOfService",
"TSPI_lineSetCallTreatment",
"TSPI_lineSetCurrentLocation",
"TSPI_lineSetDefaultMediaDetection",
"TSPI_lineSetDevConfig",
"TSPI_lineSetLineDevStatus",
"TSPI_lineSetMediaControl",
"TSPI_lineSetMediaMode",
"TSPI_lineSetStatusMessages",
"TSPI_lineSetTerminal",
"TSPI_lineSetupConference",
"TSPI_lineSetupTransfer",
"TSPI_lineSwapHold",
"TSPI_lineUncompleteCall",
"TSPI_lineUnhold",
"TSPI_lineUnpark",
"TSPI_phoneClose",
"TSPI_phoneDevSpecific",
"TSPI_phoneGetButtonInfo",
"TSPI_phoneGetData",
"TSPI_phoneGetDevCaps",
"TSPI_phoneGetDisplay",
"TSPI_phoneGetExtensionID",
"TSPI_phoneGetGain",
"TSPI_phoneGetHookSwitch",
"TSPI_phoneGetIcon",
"TSPI_phoneGetID",
"TSPI_phoneGetLamp",
"TSPI_phoneGetRing",
"TSPI_phoneGetStatus",
"TSPI_phoneGetVolume",
"TSPI_phoneNegotiateExtVersion",
"TSPI_phoneNegotiateTSPIVersion",
"TSPI_phoneOpen",
"TSPI_phoneSelectExtVersion",
"TSPI_phoneSetButtonInfo",
"TSPI_phoneSetData",
"TSPI_phoneSetDisplay",
"TSPI_phoneSetGain",
"TSPI_phoneSetHookSwitch",
"TSPI_phoneSetLamp",
"TSPI_phoneSetRing",
"TSPI_phoneSetStatusMessages",
"TSPI_phoneSetVolume",
"TSPI_providerCreateLineDevice",
"TSPI_providerCreatePhoneDevice",
"TSPI_providerEnumDevices",
"TSPI_providerFreeDialogInstance",
"TSPI_providerGenericDialogData",
"TSPI_providerInit",
"TSPI_providerShutdown",
"TSPI_providerUIIdentify",
NULL
};
PTPROVIDER pRemoteSP = (PTPROVIDER) NULL;
#if DBG
DWORD gdwDebugLevel;
#endif
struct
{
HANDLE hThread;
DWORD dwEventBufferTotalSize;
DWORD dwEventBufferUsedSize;
LPBYTE pEventBuffer;
LPBYTE pDataIn;
LPBYTE pDataOut;
PASYNCEVENTMSG pMsg;
DWORD dwMsgSize;
HANDLE hEvent;
BOOL bExit;
} gEventNotificationThreadParams;
void
EventNotificationThread(
LPVOID pParams
);
VOID
ServiceMain(
DWORD dwArgc,
LPTSTR *lpszArgv
);
void
PASCAL
LineEventProc(
HTAPILINE htLine,
HTAPICALL htCall,
DWORD dwMsg,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3
);
void
CALLBACK
LineEventProcSP(
HTAPILINE htLine,
HTAPICALL htCall,
DWORD dwMsg,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3
);
void
PASCAL
PhoneEventProc(
HTAPIPHONE htPhone,
DWORD dwMsg,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3
);
void
CALLBACK
PhoneEventProcSP(
HTAPIPHONE htPhone,
DWORD dwMsg,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3
);
PTLINELOOKUPENTRY
GetLineLookupEntry(
DWORD dwDeviceID
);
PTPHONELOOKUPENTRY
GetPhoneLookupEntry(
DWORD dwDeviceID
);
char *
PASCAL
MapResultCodeToText(
LONG lResult,
char *pszResult
);
DWORD
InitSecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor
);
void
PASCAL
GetPriorityList(
HKEY hKeyHandoffPriorities,
WCHAR *pszListName,
WCHAR **ppszPriorityList
);
void
PASCAL
SetPriorityList(
HKEY hKeyHandoffPriorities,
WCHAR *pszListName,
WCHAR *pszPriorityList
);
void
SPEventHandlerThread(
LPVOID pParams
);
VOID
__cdecl
main(
void
)
{
if (!(GetVersion() & 0x80000000)) // Win NT
{
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ TEXT("Telephony Service"), (LPSERVICE_MAIN_FUNCTION) ServiceMain },
{ NULL, NULL }
};
InitPerf();
DBGOUT((3, "main: Calling StartServiceCtrlDispatcher (NT)..."));
if (!StartServiceCtrlDispatcher(dispatchTable))
{
}
}
else // Win95
{
DBGOUT((3, "main: Calling ServiceMain (Win95)..."));
ServiceMain (0, NULL);
}
ExitProcess(0);
}
BOOL
ReportStatusToSCMgr(
DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint
)
{
SERVICE_STATUS ssStatus;
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwCurrentState = dwCurrentState;
// ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ssStatus.dwControlsAccepted = 0;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwServiceSpecificExitCode = 0;
ssStatus.dwCheckPoint = dwCheckPoint;
ssStatus.dwWaitHint = dwWaitHint;
SetServiceStatus (TapiGlobals.sshStatusHandle, &ssStatus);
return TRUE;
}
VOID
ServiceControl(
DWORD dwCtrlCode
)
{
switch (gdwServiceState)
{
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
ReportStatusToSCMgr(
gdwServiceState,
NO_ERROR,
++gdwCheckPoint,
gdwWaitHint
);
break;
default:
ReportStatusToSCMgr(
gdwServiceState,
NO_ERROR,
0,
0
);
break;
}
}
#define DEFAULTRPCMINCALLS 5
#define DEFAULTRPCMAXCALLS 5000
#define RPCMAXMAX 20000
#define RPCMINMAX 1000
VOID
ServiceMain(
DWORD dwArgc,
LPTSTR *lpszArgv
)
{
HANDLE hEvent = NULL;
DWORD dwMinCalls;
DWORD dwMaxCalls;
//
// Grab relevent values from the registry
//
{
HKEY hKey;
WCHAR szRPCMinCalls[] = L"Min";
WCHAR szRPCMaxCalls[] = L"Max";
WCHAR szTelephonyKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Telephony",
szTapisrvWaitHint[] = L"TapisrvWaitHint";
#if DBG
WCHAR szTapisrvDebugLevel[] = L"TapisrvDebugLevel";
gdwDebugLevel = 0;
#endif
if (RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
szTelephonyKey,
0,
KEY_ALL_ACCESS,
&hKey
) == ERROR_SUCCESS)
{
DWORD dwDataSize = sizeof (DWORD), dwDataType;
#if DBG
RegQueryValueExW(
hKey,
szTapisrvDebugLevel,
0,
&dwDataType,
(LPBYTE) &gdwDebugLevel,
&dwDataSize
);
dwDataSize = sizeof (DWORD);
#endif
RegQueryValueExW(
hKey,
szTapisrvWaitHint,
0,
&dwDataType,
(LPBYTE) &gdwWaitHint,
&dwDataSize
);
gdwWaitHint = (gdwWaitHint < MIN_WAIT_HINT ?
MIN_WAIT_HINT : gdwWaitHint);
dwDataSize = sizeof (DWORD);
if (RegQueryValueExW(
hKey,
szRPCMinCalls,
NULL,
&dwDataType,
(LPBYTE)&dwMinCalls,
&dwDataSize
) != ERROR_SUCCESS)
{
dwMinCalls = DEFAULTRPCMINCALLS;
}
dwDataSize = sizeof (DWORD);
if (RegQueryValueExW(
hKey,
szRPCMaxCalls,
NULL,
&dwDataType,
(LPBYTE)&dwMaxCalls,
&dwDataSize
) != ERROR_SUCCESS)
{
dwMaxCalls = DEFAULTRPCMAXCALLS;
}
DBGOUT((3, "RPC min calls %lu RPC max calls %lu", dwMinCalls, dwMaxCalls));
RegCloseKey (hKey);
// check values
if (dwMaxCalls == 0)
{
DBGOUT((3, "RPC max at 0. Changed to %lu", DEFAULTRPCMAXCALLS));
dwMaxCalls = DEFAULTRPCMAXCALLS;
}
if (dwMinCalls == 0)
{
DBGOUT((3, "RPC min at 0. Changed to %lu", DEFAULTRPCMINCALLS));
dwMinCalls = DEFAULTRPCMINCALLS;
}
if (dwMaxCalls > RPCMAXMAX)
{
DBGOUT((3, "RPC max too high at %lu. Changed to %lu", dwMaxCalls, RPCMAXMAX));
dwMaxCalls = RPCMAXMAX;
}
if (dwMinCalls > dwMaxCalls)
{
DBGOUT((3, "RPC min greater than RPC max. Changed to %lu", dwMaxCalls));
dwMinCalls = dwMaxCalls;
}
if (dwMinCalls > RPCMINMAX)
{
DBGOUT((3, "RPC min greater than allowed at %lu. Changed to %lu", dwMinCalls, RPCMINMAX));
dwMinCalls = RPCMINMAX;
}
}
}
DBGOUT((3, "ServiceMain: enter"));
FillMemory (&TapiGlobals, sizeof (TAPIGLOBALS), 0);
//
// Register the service control handler & report status to sc mgr
//
if (!(GetVersion() & 0x80000000)) // Win NT
{
TapiGlobals.sshStatusHandle = RegisterServiceCtrlHandler(
(LPCSTR)"SimpleService",
(LPHANDLER_FUNCTION)ServiceControl
);
ReportStatusToSCMgr(
(gdwServiceState = SERVICE_START_PENDING),
// service state
NO_ERROR, // exit code
(gdwCheckPoint = 0), // checkpoint
gdwWaitHint // wait hint
);
}
//
//
//
InitializeCriticalSection (&gSafeMutexCritSec);
InitializeCriticalSection (&gRemoteCliEventBufCritSec);
InitializeCriticalSection (&gRequestIDCritSec);
InitializeCriticalSection (&gPriorityListCritSec);
InitializeCriticalSection (&gSPEventQueueCritSec);
ghPendingSPEventsEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) NULL,
TRUE, // manual reset
FALSE, // non-signaled
NULL // unnamed
);
TapiGlobals.hProcess = GetCurrentProcess();
{
DWORD dwTID;
HANDLE hThread;
if (!(hThread = CreateThread(
(LPSECURITY_ATTRIBUTES) NULL,
0,
(LPTHREAD_START_ROUTINE) SPEventHandlerThread,
NULL,
0,
&dwTID
)))
{
DBGOUT((
1,
"CreateThread('SPEventHandlerThread') failed, err=%d",
GetLastError()
));
}
CloseHandle (hThread);
}
//
// Init some globals
//
TapiGlobals.hMutex = MyCreateMutex();
TapiGlobals.hAsyncRequestIDMutex = MyCreateMutex();
{
DWORD dwSize = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
TapiGlobals.pszComputerName = ServerAlloc (dwSize);
GetComputerNameW(TapiGlobals.pszComputerName, &dwSize);
TapiGlobals.dwComputerNameSize = (1 +
lstrlenW(TapiGlobals.pszComputerName)) * sizeof(WCHAR);
}
// BUGBUG ServiceMain: LocalSystem hack, can nuke when srv acct stuff correct
{
char szUserName[32], szDomainName[32], szPassword[32];
HKEY hKey;
DWORD dwDataSize;
DWORD dwDataType;
DWORD dwTemp;
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKey
);
dwDataSize = sizeof(dwTemp);
dwTemp = 0;
RegQueryValueEx(
hKey,
"EnableSharing",
0,
&dwDataType,
(LPBYTE) &dwTemp,
&dwDataSize
);
if (dwTemp)
{
dwDataSize = sizeof(szUserName);
RegQueryValueEx(
hKey,
"User",
0,
&dwDataType,
(LPBYTE) szUserName,
&dwDataSize
);
szUserName[dwDataSize] = '\0';
dwDataSize = sizeof(szDomainName);
RegQueryValueEx(
hKey,
"Domain",
0,
&dwDataType,
(LPBYTE)szDomainName,
&dwDataSize
);
szDomainName[dwDataSize] = '\0';
dwDataSize = sizeof(szPassword);
RegQueryValueEx(
hKey,
"Password",
0,
&dwDataType,
(LPBYTE)szPassword,
&dwDataSize
);
szPassword[dwDataSize] = '\0';
if (!LogonUser(
szUserName,
szDomainName,
szPassword,
LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,
&ghToken
))
{
DBGOUT((
1,
"LogonUser(usr=%s,domain=%s) failed, err=%d",
szUserName,
szDomainName,
GetLastError()
));
ghToken = NULL;
}
}
else
{
ghToken = NULL;
}
RegCloseKey(
hKey
);
}
//
// Alloc the EventNotificationThread resources and start the thread
//
// BUGBUG ServiceMain: hack for spinning EventNotifyThd (sharing enabled)
if (ghToken) // hackhack
{
gEventNotificationThreadParams.dwEventBufferTotalSize = 1024;
gEventNotificationThreadParams.dwEventBufferUsedSize = 0;
if (!(gEventNotificationThreadParams.pEventBuffer = ServerAlloc(
gEventNotificationThreadParams.dwEventBufferTotalSize
)))
{
}
gEventNotificationThreadParams.pDataIn =
gEventNotificationThreadParams.pDataOut =
gEventNotificationThreadParams.pEventBuffer;
gEventNotificationThreadParams.dwMsgSize = 512;
if (!(gEventNotificationThreadParams.pMsg = ServerAlloc(
gEventNotificationThreadParams.dwMsgSize
)))
{
}
if (!(gEventNotificationThreadParams.hEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) NULL, // no security attrs
TRUE, // manual reset
FALSE, // initially non-signaled
NULL // unnamed
)))
{
}
gEventNotificationThreadParams.bExit = FALSE;
{
DWORD dwTID;
if (!(gEventNotificationThreadParams.hThread = CreateThread(
(LPSECURITY_ATTRIBUTES) NULL,
0,
(LPTHREAD_START_ROUTINE) EventNotificationThread,
NULL,
0,
&dwTID
)))
{
DBGOUT((
1,
"CreateThread('EventNotificationThread') failed, err=%d",
GetLastError()
));
}
}
}
//
// Init Rpc server
//
{
RPC_STATUS status;
// unsigned char * pszSecurity = NULL;
// min and max calls are read from registry above
// unsigned int cMinCalls = 5;
// unsigned int cMaxCalls = 5000;
unsigned int fDontWait = FALSE;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitSecurityDescriptor (&sd);
sa.nLength = sizeof(SECURITY_ATTRIBUTES) ;
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE ;
status = RpcServerUseProtseqEp(
"ncacn_np",
(unsigned int) dwMaxCalls,
"\\pipe\\tapsrv",
&sd
);
DBGOUT((3, "RpcServerUseProtseqEp(np) ret'd %d", status));
if (status)
{
}
status = RpcServerUseProtseqEp(
"ncalrpc",
(unsigned int) dwMaxCalls,
"tapsrvlpc",
&sd
);
DBGOUT((3, "RpcServerUseProtseqEp(lrpc) ret'd %d", status));
if (status)
{
}
status = RpcServerRegisterIf(
tapsrv_ServerIfHandle, // interface to register
NULL, // MgrTypeUuid
NULL // MgrEpv; null means use default
);
DBGOUT((3, "RpcServerRegisterIf ret'd %d", status));
if (status)
{
}
if (!(GetVersion() & 0x80000000)) // Win NT
{
ReportStatusToSCMgr(
(gdwServiceState = SERVICE_RUNNING),
// service state
NO_ERROR, // exit code
0, // checkpoint
0 // wait hint
);
}
else // Win95
{
if (!(hEvent = CreateEvent (NULL, TRUE, FALSE, "TapiSrvInited")))
{
DBGOUT((
1,
"CreateEvent ('TapiSrvInited') failed, err=%d",
GetLastError()
));
}
SetEvent (hEvent);
}
DBGOUT((3, "Calling RpcServerListen..."));
status = RpcServerListen(
(unsigned int)dwMinCalls,
(unsigned int)dwMaxCalls,
fDontWait
);
DBGOUT((3, "RpcServerListen ret'd %d", status));
if (status)
{
}
if (fDontWait)
{
DBGOUT((3, "Calling RpcMgmtWaitServerListen..."));
status = RpcMgmtWaitServerListen(); // wait operation
DBGOUT((3, "RpcMgmtWaitServerListen ret'd %d", status));
if (status)
{
}
}
}
//
// Free various resources
//
CloseHandle (TapiGlobals.hMutex);
CloseHandle (TapiGlobals.hAsyncRequestIDMutex);
//
// Wait for the EventHandlerThread to terminate, then clean up
// the related resources
//
// BUGBUG ServiceMain: another LocalSystem hack
if (ghToken) // hackhack
{
CloseHandle (ghToken);
gEventNotificationThreadParams.bExit = TRUE;
while (WaitForSingleObject (gEventNotificationThreadParams.hThread, 0) !=
WAIT_OBJECT_0)
{
SetEvent (gEventNotificationThreadParams.hEvent);
Sleep (0);
}
CloseHandle (gEventNotificationThreadParams.hThread);
CloseHandle (gEventNotificationThreadParams.hEvent);
ServerFree (gEventNotificationThreadParams.pEventBuffer);
ServerFree (gEventNotificationThreadParams.pMsg);
}
DeleteCriticalSection (&gSafeMutexCritSec);
DeleteCriticalSection (&gRemoteCliEventBufCritSec);
DeleteCriticalSection (&gRequestIDCritSec);
DeleteCriticalSection (&gPriorityListCritSec);
//DeleteCriticalSection (&gSPEventQueueCritSec);
if (!(GetVersion() & 0x80000000)) // Win NT
{
//
// Report the stopped status to the service control manager.
//
if (TapiGlobals.sshStatusHandle)
{
ReportStatusToSCMgr ((gdwServiceState = SERVICE_STOPPED), 0, 0, 0);
}
}
else // Win95
{
// BUGBUG ServiceMain: overlap prob (cli starts while we're shutting down)
CloseHandle (hEvent);
}
//
// When SERVICE MAIN FUNCTION returns in a single service
// process, the StartServiceCtrlDispatcher function in
// the main thread returns, terminating the process.
//
DBGOUT((3, "ServiceMain: exit"));
return;
}
void
PASCAL
QueueSPEvent(
PSPEVENT pSPEvent
)
{
//
// Safely queue an SP event
//
EnterCriticalSection (&gSPEventQueueCritSec);
if (gbQueueSPEvents == TRUE)
{
if (gpYoungestSPEvent)
{
gpYoungestSPEvent->pNext = pSPEvent;
}
else
{
//
// The queue was empty, so init the oldest event ptr &
// set the event to wake up the SPEVentHandlerThread
//
gpOldestSPEvent = pSPEvent;
SetEvent (ghPendingSPEventsEvent);
}
gpYoungestSPEvent = pSPEvent;
}
LeaveCriticalSection (&gSPEventQueueCritSec);
}
BOOL
PASCAL
DequeueSPEvent(
PSPEVENT *ppSPEvent
)
{
BOOL bResult;
//
// Safely try to remove the oldest SP event from the queue
//
EnterCriticalSection (&gSPEventQueueCritSec);
if (gpOldestSPEvent)
{
*ppSPEvent = gpOldestSPEvent;
if (!(gpOldestSPEvent = gpOldestSPEvent->pNext))
{
//
// This was the last event in the queue, so nullify
// the youngest event ptr and reset the event to put
// the SPEVentHandlerThread to sleep
//
gpYoungestSPEvent = (PSPEVENT) NULL;
ResetEvent (ghPendingSPEventsEvent);
}
bResult = TRUE;
}
else
{
bResult = FALSE;
ResetEvent (ghPendingSPEventsEvent);
}
LeaveCriticalSection (&gSPEventQueueCritSec);
return bResult;
}
void
SPEventHandlerThread(
LPVOID pParams
)
{
//
// This thread processes the events & completion notifications
// indicated to us by an SP at a previous time/thread context.
// There are a couple of reasons for doing this in a separate
// thread rather than within the SP's thread context:
//
// 1. for some msgs (i.e. XXX_CLOSE) TAPI will call back
// into the SP, which it may not be expecting
//
// 2. we don't want to block the SP's thread by processing
// the msg, forwarding it on to the appropriate clients,
// etc
//
DBGOUT((
3,
"SPEventHandlerThread: enter (pid=%d)",
GetCurrentThreadId()
));
while (1)
{
PSPEVENT pSPEvent;
WaitForSingleObject (ghPendingSPEventsEvent, INFINITE);
while (DequeueSPEvent (&pSPEvent))
{
switch (pSPEvent->dwType)
{
case SP_LINE_EVENT:
LineEventProc(
pSPEvent->htLine,
pSPEvent->htCall,
pSPEvent->dwMsg,
pSPEvent->dwParam1,
pSPEvent->dwParam2,
pSPEvent->dwParam3
);
break;
case TASYNC_KEY:
CompletionProc(
(PASYNCREQUESTINFO) pSPEvent,
((PASYNCREQUESTINFO) pSPEvent)->lResult
);
break;
case SP_PHONE_EVENT:
PhoneEventProc(
pSPEvent->htPhone,
pSPEvent->dwMsg,
pSPEvent->dwParam1,
pSPEvent->dwParam2,
pSPEvent->dwParam3
);
break;
}
ServerFree (pSPEvent);
}
//
// Check to see if all the clients are gone, and if so wait a
// while to see if anyone else attaches. If no one else attaches
// in the specified amount of time then shut down.
//
if (TapiGlobals.ptClients == NULL)
{
DWORD dwDeferredShutdownTimeout, dwSleepInterval,
dwLoopCount, i;
RPC_STATUS status;
// BUGBUG SPEventHandlerThread:
dwDeferredShutdownTimeout = 30; // 30 seconds
dwSleepInterval = 250; // 250 milliseconds
dwLoopCount = dwDeferredShutdownTimeout * 1000 / dwSleepInterval;
for (i = 0; i < dwLoopCount; i++)
{
Sleep (dwSleepInterval);
if (TapiGlobals.ptClients != NULL)
{
break;
}
}
if (i == dwLoopCount && TapiGlobals.ptClients == NULL)
{
if (!(GetVersion() & 0x80000000)) // Win NT
{
if (TapiGlobals.sshStatusHandle)
{
ReportStatusToSCMgr(
(gdwServiceState = SERVICE_STOP_PENDING),
0,
(gdwCheckPoint = 0),
gdwWaitHint
);
}
}
else // Win95
{
}
DBGOUT((3, "Calling RpcMgmtStopServerListening"));
status = RpcMgmtStopServerListening (NULL);
DBGOUT((
3,
"RpcMgmtStopServerListening returned: %d",
status
));
if (status)
{
//exit (status);
}
DBGOUT((3, "Calling RpcServerUnregisterIf"));
status = RpcServerUnregisterIf (NULL, NULL, FALSE);
DBGOUT((3, "RpcServerUnregisterIf returned %d", status));
DBGOUT((
3,
"SPEventHandlerThread: exit (pid=%d)",
GetCurrentThreadId()
));
ExitThread (0);
}
}
}
}
DWORD
InitSecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
//
// Note: this code was borrowed from Steve Cobb, who borrowed from RASMAN
//
DWORD dwResult;
DWORD cbDaclSize;
PULONG pSubAuthority;
PSID pObjSid = NULL;
PACL pDacl = NULL;
SID_IDENTIFIER_AUTHORITY SidIdentifierWorldAuth =
SECURITY_WORLD_SID_AUTHORITY;
//
// The do - while(FALSE) statement is used so that the break statement
// maybe used insted of the goto statement, to execute a clean up and
// and exit action.
//
do
{
dwResult = 0;
//
// Set up the SID for the admins that will be allowed to have
// access. This SID will have 1 sub-authorities
// SECURITY_BUILTIN_DOMAIN_RID.
//
if (!(pObjSid = (PSID) ServerAlloc (GetSidLengthRequired (1))))
{
dwResult = GetLastError();
break;
}
if (!InitializeSid (pObjSid, &SidIdentifierWorldAuth, 1))
{
dwResult = GetLastError();
DBGOUT((1, "InitializeSid() failed, err=%d", dwResult));
break;
}
//
// Set the sub-authorities
//
pSubAuthority = GetSidSubAuthority (pObjSid, 0);
*pSubAuthority = SECURITY_WORLD_RID;
//
// Set up the DACL that will allow all processeswith the above
// SID all access. It should be large enough to hold all ACEs.
//
cbDaclSize = sizeof(ACCESS_ALLOWED_ACE) +
GetLengthSid (pObjSid) +
sizeof(ACL);
if (!(pDacl = (PACL) ServerAlloc (cbDaclSize)))
{
dwResult = GetLastError ();
break;
}
if (!InitializeAcl (pDacl, cbDaclSize, ACL_REVISION2))
{
dwResult = GetLastError();
DBGOUT((1, "InitializeAcl() failed, err=%d", dwResult));
break;
}
//
// Add the ACE to the DACL
//
if (!AddAccessAllowedAce(
pDacl,
ACL_REVISION2,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
pObjSid
))
{
dwResult = GetLastError();
DBGOUT((1, "AddAccessAllowedAce() failed, err=%d", dwResult));
break;
}
//
// Create the security descriptor an put the DACL in it.
//
if (!InitializeSecurityDescriptor (pSecurityDescriptor, 1))
{
dwResult = GetLastError();
DBGOUT((
1,
"InitializeSecurityDescriptor() failed, err=%d",
dwResult
));
break;
}
if (!SetSecurityDescriptorDacl(
pSecurityDescriptor,
TRUE,
pDacl,
FALSE
))
{
dwResult = GetLastError();
DBGOUT((1, "SetSecurityDescriptorDacl() failed, err=%d",dwResult));
break;
}
//
// Set owner for the descriptor
//
if (!SetSecurityDescriptorOwner(
pSecurityDescriptor,
NULL,
FALSE
))
{
dwResult = GetLastError();
DBGOUT((1, "SetSecurityDescriptorOwnr() failed, err=%d",dwResult));
break;
}
//
// Set group for the descriptor
//
if (!SetSecurityDescriptorGroup(
pSecurityDescriptor,
NULL,
FALSE
))
{
dwResult = GetLastError();
DBGOUT((1,"SetSecurityDescriptorGroup() failed, err=%d",dwResult));
break;
}
} while (FALSE);
return dwResult;
}
PASYNCEVENTMSG
GetEventFromQueue(
void
)
{
DWORD dwUsedSize, dwMoveSize, dwMoveSizeWrapped;
PASYNCEVENTMSG pMsg = gEventNotificationThreadParams.pMsg;
//
// Enter the critical section to serialize access to the event
// queue, and grab an event from the queue. Copy it to our local
// event buf so that we can leave the critical section asap and
// not block other threads writing to the queue.
//
EnterCriticalSection (&gRemoteCliEventBufCritSec);
//
// If there are no events in the queue return NULL
//
if (gEventNotificationThreadParams.dwEventBufferUsedSize == 0)
{
pMsg = NULL;
goto GetEventFromQueue_done;
}
//
// Copy the fixed portion of the msg to the local buf
//
dwUsedSize = (gEventNotificationThreadParams.pEventBuffer +
gEventNotificationThreadParams.dwEventBufferTotalSize) -
gEventNotificationThreadParams.pDataOut;
if (dwUsedSize >= sizeof (ASYNCEVENTMSG))
{
dwMoveSize = sizeof (ASYNCEVENTMSG);
dwMoveSizeWrapped = 0;
}
else
{
dwMoveSize = dwUsedSize;
dwMoveSizeWrapped = sizeof (ASYNCEVENTMSG) - dwUsedSize;
}
CopyMemory (pMsg, gEventNotificationThreadParams.pDataOut, dwMoveSize);
if (dwMoveSizeWrapped)
{
CopyMemory(
((LPBYTE) pMsg) + dwMoveSize,
gEventNotificationThreadParams.pEventBuffer,
dwMoveSizeWrapped
);
gEventNotificationThreadParams.pDataOut =
gEventNotificationThreadParams.pEventBuffer + dwMoveSizeWrapped;
}
else
{
gEventNotificationThreadParams.pDataOut += dwMoveSize;
}
//
// See if there's any extra data in this msg
//
if (pMsg->dwTotalSize > sizeof (ASYNCEVENTMSG))
{
BOOL bCopy = TRUE;
//
// See if we need to grow the msg buffer
//
if (pMsg->dwTotalSize > gEventNotificationThreadParams.dwMsgSize)
{
DWORD dwNewMsgSize = pMsg->dwTotalSize + 256;
if ((pMsg = ServerAlloc (dwNewMsgSize)))
{
CopyMemory(
pMsg,
gEventNotificationThreadParams.pMsg,
sizeof(ASYNCEVENTMSG)
);
ServerFree (gEventNotificationThreadParams.pMsg);
gEventNotificationThreadParams.pMsg = pMsg;
gEventNotificationThreadParams.dwMsgSize = dwNewMsgSize;
}
else
{
//
// Couldn't alloc a bigger buf, so try to complete this
// msg as gracefully as possible
//
bCopy = FALSE;
switch (pMsg->dwMsg)
{
case LINE_REPLY:
pMsg->dwParam2 = LINEERR_NOMEM;
break;
case PHONE_REPLY:
pMsg->dwParam2 = PHONEERR_NOMEM;
break;
default:
// BUGBUG GetEventFromQueue: any other msgs to special case?
break;
}
}
}
dwUsedSize = (gEventNotificationThreadParams.pEventBuffer +
gEventNotificationThreadParams.dwEventBufferTotalSize) -
gEventNotificationThreadParams.pDataOut;
if (dwUsedSize >= (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG)))
{
dwMoveSize = pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG);
dwMoveSizeWrapped = 0;
}
else
{
dwMoveSize = dwUsedSize;
dwMoveSizeWrapped = (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG)) -
dwUsedSize;
}
if (bCopy)
{
CopyMemory(
pMsg + 1,
gEventNotificationThreadParams.pDataOut,
dwMoveSize
);
}
if (dwMoveSizeWrapped)
{
if (bCopy)
{
CopyMemory(
((LPBYTE) (pMsg + 1)) + dwMoveSize,
gEventNotificationThreadParams.pEventBuffer,
dwMoveSizeWrapped
);
}
gEventNotificationThreadParams.pDataOut =
gEventNotificationThreadParams.pEventBuffer +
dwMoveSizeWrapped;
}
else
{
gEventNotificationThreadParams.pDataOut += dwMoveSize;
}
}
gEventNotificationThreadParams.dwEventBufferUsedSize -= pMsg->dwTotalSize;
GetEventFromQueue_done:
LeaveCriticalSection (&gRemoteCliEventBufCritSec);
ResetEvent (gEventNotificationThreadParams.hEvent);
return pMsg;
}
void
EventNotificationThread(
LPVOID pParams
)
{
PASYNCEVENTMSG pMsg;
DBGOUT((3, "EventNotificationThread: enter"));
ImpersonateLoggedOnUser (ghToken);
while (1)
{
WaitForSingleObject (gEventNotificationThreadParams.hEvent, INFINITE);
if (gEventNotificationThreadParams.bExit)
{
break;
}
while ((pMsg = GetEventFromQueue()))
{
PCONTEXT_HANDLE_TYPE2 phContext;
//
// Make sure the msg is destined for a valid client
//
// !!! Note the overlaoding of the pMsg->dwCallbackInst field
// (see corresponding note in WriteEventBuffer())
//
try
{
PTCLIENT ptClient = (PTCLIENT) pMsg->dwCallbackInst;
phContext = ptClient->phContext;
if (ptClient->dwKey != TCLIENT_KEY)
{
continue;
}
}
myexcept
{
continue;
}
//
// Send the event to the client
//
RpcTryExcept
{
RemoteSPEventProc(
phContext,
(unsigned char *) pMsg,
pMsg->dwTotalSize
);
}
RpcExcept (1)
{
unsigned long ulResult = RpcExceptionCode();
DBGOUT((
3,
"EventNotificationThread: exception #%d",
ulResult
));
if (ulResult == RPC_S_SERVER_TOO_BUSY)
{
// BUGBUG EventNotificationThread: timeout, then try the op again
}
else
{
// BUGBUG EventNotificationThread: consider shutting down the rpc connection
// (& sending REINITs?)
}
}
RpcEndExcept
}
}
RevertToSelf();
DBGOUT((3, "EventNotificationThread: exit"));
ExitThread (0);
}
void
__RPC_FAR *
__RPC_API
midl_user_allocate(
size_t len
)
{
return (ServerAlloc(len));
}
void
__RPC_API
midl_user_free(
void __RPC_FAR * ptr
)
{
ServerFree (ptr);
}
LONG
ClientAttach(
PCONTEXT_HANDLE_TYPE *pphContext,
long lProcessID,
long *phAsyncEventsEvent,
wchar_t *pszDomainUser,
wchar_t *pszMachine
)
{
PTCLIENT ptClient;
DBGOUT((
3,
"ClientAttach: enter, pid=x%x, user='%ls', machine='%ls'",
lProcessID,
pszDomainUser,
pszMachine
));
//
// Alloc & init a tClient struct
//
if (!(ptClient = ServerAlloc (sizeof(TCLIENT))))
{
goto ClientAttach_error0;
}
if (!(ptClient->hMutex = MyCreateMutex()))
{
goto ClientAttach_error1;
}
ptClient->dwUserNameSize = (lstrlenW(pszDomainUser) + 1) * sizeof(WCHAR);
if (!(ptClient->pszUserName = ServerAlloc (ptClient->dwUserNameSize)))
{
goto ClientAttach_error2;
}
lstrcpyW(ptClient->pszUserName, pszDomainUser);
if (lProcessID == 0xffffffff)
{
//
// This is a remote client
//
ptClient->hProcess = (HANDLE) 0xffffffff;
ptClient->dwComputerNameSize = (1 + lstrlenW(pszMachine)) * sizeof(WCHAR);
ptClient->pszComputerName = ServerAlloc (ptClient->dwComputerNameSize);
lstrcpyW(ptClient->pszComputerName, pszMachine);
//
//
//
// BUGBUG ClientAttach: may need to serialize this for safe access to RemoteSP
{
RPC_STATUS status;
WCHAR *pszStringBinding = NULL, *pszMachineName;
PCONTEXT_HANDLE_TYPE2 phContext = NULL;
pszMachineName = ServerAlloc ((lstrlenW(pszMachine) + 3) * sizeof(WCHAR));
pszMachineName[0] = pszMachineName[1] = '\\';
lstrcpyW(pszMachineName + 2, pszMachine);
if (!ImpersonateLoggedOnUser (ghToken))
{
DBGOUT((
1,
"ClientAttach: ImpersonateLoggedOnUser failed, err=%d",
GetLastError()
));
}
status = RpcStringBindingComposeW(
NULL, // uuid
L"ncacn_np", // prot
pszMachineName, // server name
L"\\pipe\\remotesp", // interface name
NULL, // options
&pszStringBinding
);
ServerFree (pszMachineName);
if (status)
{
DBGOUT((
0,
"RpcStringBindingCompose failed: err=%d, szNetAddr='%s'",
status,
pszMachineName
));
}
status = RpcBindingFromStringBindingW(
pszStringBinding,
&hRemoteSP
);
if (status)
{
DBGOUT((
0,
"RpcBindingFromStringBinding failed, err=%d, szBinding='%s'",
status,
pszStringBinding
));
}
RpcTryExcept
{
RemoteSPAttach ((PCONTEXT_HANDLE_TYPE2 *) &phContext);
}
RpcExcept (1)
{
// BUGBUG ClientAttach: handle rpcexcept
}
RpcEndExcept
RpcBindingFree (&hRemoteSP);
RpcStringFreeW(&pszStringBinding);
RevertToSelf();
ptClient->phContext = phContext;
}
}
else if ((ptClient->hProcess = OpenProcess(
PROCESS_DUP_HANDLE | SYNCHRONIZE | STANDARD_RIGHTS_REQUIRED,
FALSE,
lProcessID
)))
{
//
// This is a local client, so set up all the event buffer stuff
//
ptClient->dwComputerNameSize = TapiGlobals.dwComputerNameSize;
ptClient->pszComputerName = TapiGlobals.pszComputerName;
if (!(ptClient->hEventBufferMutex = MyCreateMutex()))
{
goto ClientAttach_error3;
}
if (!(ptClient->hValidEventBufferDataEvent = CreateEvent(
(LPSECURITY_ATTRIBUTES) NULL,
TRUE, // manual-reset
FALSE, // nonsignaled
NULL // unnamed
)))
{
CloseHandle (ptClient->hEventBufferMutex);
goto ClientAttach_error3;
}
if (!(ptClient->pEventBuffer = ServerAlloc (INITIAL_EVENT_BUFFER_SIZE)))
{
CloseHandle (ptClient->hEventBufferMutex);
CloseHandle (ptClient->hValidEventBufferDataEvent);
goto ClientAttach_error3;
}
ptClient->dwEventBufferTotalSize = INITIAL_EVENT_BUFFER_SIZE;
ptClient->dwEventBufferUsedSize = 0;
ptClient->pDataIn = ptClient->pDataOut = ptClient->pEventBuffer;
if (!DuplicateHandle(
TapiGlobals.hProcess,
ptClient->hValidEventBufferDataEvent,
ptClient->hProcess,
(HANDLE *) phAsyncEventsEvent,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
DBGOUT((1, "ClientAttach: DupHandle failed, err=%d", GetLastError()));
}
//
// Load the priority lists if we haven't already done so
//
if (gbPriorityListsInitialized == FALSE)
{
RPC_STATUS status;
if ((status = RpcImpersonateClient (0)) != RPC_S_OK)
{
DBGOUT((2, "ClientAttach: RpcImpersonateClient failed, err=%d", status));
}
EnterCriticalSection (&gPriorityListCritSec);
if (gbPriorityListsInitialized == FALSE)
{
HKEY hKeyHandoffPriorities;
LONG lResult;
DWORD i;
gbPriorityListsInitialized = TRUE;
if ((lResult = RegOpenKeyEx(
HKEY_CURRENT_USER,
gszRegKeyHandoffPriorities,
0,
KEY_READ,
&hKeyHandoffPriorities
)) == ERROR_SUCCESS)
{
// BUGBUG ClientAttach: ext media priorities (load pri lists)
for (i = 1; gaszMediaModes[i] != NULL; i++)
{
GetPriorityList(
hKeyHandoffPriorities,
gaszMediaModes[i],
TapiGlobals.apszPriorityList + i
);
}
GetPriorityList(
hKeyHandoffPriorities,
gszRequestMakeCallW,
&TapiGlobals.pszReqMakeCallPriList
);
GetPriorityList(
hKeyHandoffPriorities,
gszRequestMediaCallW,
&TapiGlobals.pszReqMediaCallPriList
);
RegCloseKey (hKeyHandoffPriorities);
}
else
{
DBGOUT((
2,
"RegOpenKey('\\HandoffPri') failed, err=%ld",
lResult
));
}
}
LeaveCriticalSection (&gPriorityListCritSec);
if (status == RPC_S_OK)
{
RpcRevertToSelf ();
}
}
}
else
{
DBGOUT((
1,
"OpenProcess(pid=x%x) failed, err=%d",
lProcessID,
GetLastError()
));
goto ClientAttach_error3;
}
//
// Add tClient to global list
//
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
if ((ptClient->pNext = TapiGlobals.ptClients))
{
ptClient->pNext->pPrev = ptClient;
}
TapiGlobals.ptClients = ptClient;
ptClient->dwKey = TCLIENT_KEY;
ReleaseMutex (TapiGlobals.hMutex);
//
// Fill in return values
//
*pphContext = (PCONTEXT_HANDLE_TYPE) ptClient;
PerfBlock.dwClientApps++;
return 0;
//
// Error cleanup
//
ClientAttach_error3:
ServerFree (ptClient->pszUserName);
ClientAttach_error2:
CloseHandle (ptClient->hMutex);
ClientAttach_error1:
ServerFree (ptClient);
ClientAttach_error0:
return LINEERR_NOMEM;
}
void
ClientRequest(
PCONTEXT_HANDLE_TYPE phContext,
unsigned char *pBuffer,
long lNeededSize,
long *plUsedSize
)
{
PTAPI32_MSG pMsg = (PTAPI32_MSG) pBuffer;
DWORD dwFuncIndex = pMsg->u.Req_Func;
//DBGOUT((
// 4,
// "ClientRequest: phCntxt=x%, reqType x%x, needed=x%x, used=x%x",
// phContext,
// dwFuncIndex,
// lNeededSize,
// *plUsedSize
// ));
pMsg->u.Ack_ReturnValue = TAPI_SUCCESS;
pMsg->hRpcClientInst = (DWORD) phContext;
*plUsedSize = sizeof(LONG);
(*gaFuncs[dwFuncIndex])(
pMsg,
pBuffer + sizeof(TAPI32_MSG),
plUsedSize
);
}
void
ClientDetach(
PCONTEXT_HANDLE_TYPE *pphContext
)
{
DBGOUT((3, "ClientDetach: enter"));
{
PTCLIENT ptClient = (PTCLIENT) *pphContext;
if (ptClient->hProcess != (HANDLE) 0xffffffff)
{
//
// Write the pri lists to the registry when a local client
// detaches.
//
// BUGBUG This isn't the most efficient thing in the world.
// Need to investigate a way to guarantee that we
// can impersonate a local client on shutdown, so we
// only have to do this once (need to impersonate in
// order to access current user keys)
//
{
HKEY hKeyHandoffPriorities;
LONG lResult;
DWORD dwDisposition, i;
RPC_STATUS status;
if ((status = RpcImpersonateClient (0)) != RPC_S_OK)
{
DBGOUT((2, "ClientDetach: RpcImpersonateClient failed, err=%d", status));
}
if ((lResult = RegCreateKeyEx(
HKEY_CURRENT_USER,
gszRegKeyHandoffPriorities,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
(LPSECURITY_ATTRIBUTES) NULL,
&hKeyHandoffPriorities,
&dwDisposition
)) == ERROR_SUCCESS)
{
EnterCriticalSection (&gPriorityListCritSec);
for (i = 1; gaszMediaModes[i] != NULL; i++)
{
SetPriorityList(
hKeyHandoffPriorities,
gaszMediaModes[i],
TapiGlobals.apszPriorityList[i]
);
}
SetPriorityList(
hKeyHandoffPriorities,
gszRequestMakeCallW,
TapiGlobals.pszReqMakeCallPriList
);
SetPriorityList(
hKeyHandoffPriorities,
gszRequestMediaCallW,
TapiGlobals.pszReqMediaCallPriList
);
LeaveCriticalSection (&gPriorityListCritSec);
RegCloseKey (hKeyHandoffPriorities);
}
else
{
DBGOUT((
3,
"RegCreateKeyEx('\\HandoffPri') failed, err=%ld",
lResult
));
}
if (status == RPC_S_OK)
{
RpcRevertToSelf ();
}
}
}
}
PCONTEXT_HANDLE_TYPE_rundown (*pphContext);
*pphContext = (PCONTEXT_HANDLE_TYPE) NULL;
PerfBlock.dwClientApps--;
DBGOUT((3, "ClientDetach: exit"));
}
void
__RPC_USER
PCONTEXT_HANDLE_TYPE_rundown(
PCONTEXT_HANDLE_TYPE phContext
)
{
PTCLIENT ptClient = (PTCLIENT) phContext;
//DBGOUT((
// 3,
// "PCONTEXT_HANDLE_TYPE_rundown: enter, phContext=x%x",
// phContext
// ));
//
// Mark client as invalid
//
ptClient->dwKey = INVAL_KEY;
//
// Remove it from global list
//
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
if (ptClient->pNext)
{
ptClient->pNext->pPrev = ptClient->pPrev;
}
if (ptClient->pPrev)
{
ptClient->pPrev->pNext = ptClient->pNext;
}
else
{
TapiGlobals.ptClients = ptClient->pNext;
}
ReleaseMutex (TapiGlobals.hMutex);
//
// If client was remote then detach
//
if (ptClient->hProcess == (HANDLE) 0xffffffff)
{
RpcTryExcept
{
RemoteSPDetach (&ptClient->phContext);
}
RpcExcept (1)
{
unsigned long ulResult = RpcExceptionCode();
DBGOUT((
3,
"rundown: exception #%d detaching from remotesp",
ulResult
));
if (ulResult == RPC_S_SERVER_TOO_BUSY)
{
// BUGBUG rundown: timeout, then try the op again
}
else
{
// BUGBUG rundown: consider shutting down the rpc connection (& send REINITs?)
}
}
RpcEndExcept
}
//
// Close all XxxApps
//
while (ptClient->ptLineApps)
{
DestroytLineApp (ptClient->ptLineApps);
}
while (ptClient->ptPhoneApps)
{
DestroytPhoneApp (ptClient->ptPhoneApps);
}
//
// Clean up any existing ProviderXxx dialog instances
//
{
PTAPIDIALOGINSTANCE pProviderXxxDlgInst =
ptClient->pProviderXxxDlgInsts,
pNextProviderXxxDlgInst;
while (pProviderXxxDlgInst)
{
FREEDIALOGINSTANCE_PARAMS params =
{
0,
ptClient,
(HTAPIDIALOGINSTANCE) pProviderXxxDlgInst,
LINEERR_OPERATIONFAILED
};
pNextProviderXxxDlgInst = pProviderXxxDlgInst->pNext;
FreeDialogInstance (&params, NULL, NULL);
pProviderXxxDlgInst = pNextProviderXxxDlgInst;
}
}
//
// Clean up associated resources
//
CloseHandle (ptClient->hMutex);
if (ptClient->hProcess != (HANDLE) 0xffffffff)
{
CloseHandle (ptClient->hProcess);
CloseHandle (ptClient->hValidEventBufferDataEvent);
CloseHandle (ptClient->hEventBufferMutex);
ServerFree (ptClient->pEventBuffer);
}
ServerFree (ptClient->pszUserName);
if (ptClient->pszComputerName != TapiGlobals.pszComputerName)
{
ServerFree (ptClient->pszComputerName);
}
ServerFree (ptClient);
//
// If this was the last client then alert the SPEventHandlerThread
// that it should begin it's deferred shutdown countdown
//
if (!TapiGlobals.ptClients)
{
EnterCriticalSection (&gSPEventQueueCritSec);
SetEvent (ghPendingSPEventsEvent);
LeaveCriticalSection (&gSPEventQueueCritSec);
}
//DBGOUT((3, "PCONTEXT_HANDLE_TYPE_rundown: exit"));
}
LPVOID
WINAPI
ServerAlloc(
DWORD dwSize
)
{
LPBYTE p;
LPDWORD pAligned;
//
// Alloc 16 extra bytes so we can make sure the pointer we pass back
// is 64-bit aligned & have space to store the original pointer
//
if ((p = (LPBYTE) LocalAlloc (LPTR, dwSize + 16)))
{
pAligned = (LPDWORD) (p + 8 - (((DWORD) p) & 0x7));
*pAligned = (DWORD) p;
pAligned++;
pAligned++;
}
else
{
static BOOL fBeenThereDoneThat = FALSE;
static DWORD fBreakOnAllocFailed = 0;
// send reinit msg?
DBGOUT((
1,
"ServerAlloc: LocalAlloc (x%lx) failed, err=x%lx",
dwSize,
GetLastError())
);
pAligned = NULL;
#if DBG
if ( !fBeenThereDoneThat )
{
HKEY hKey;
WCHAR szTelephonyKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Telephony";
WCHAR szTapisrvDebugBreak[] = L"TapisrvDebugBreak";
fBeenThereDoneThat = TRUE;
if (RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
szTelephonyKey,
0,
KEY_ALL_ACCESS,
&hKey
) == ERROR_SUCCESS)
{
DWORD dwDataSize = sizeof (DWORD), dwDataType;
RegQueryValueExW(
hKey,
szTapisrvDebugBreak,
0,
&dwDataType,
(LPBYTE) &fBreakOnAllocFailed,
&dwDataSize
);
dwDataSize = sizeof (DWORD);
RegCloseKey (hKey);
}
}
if ( fBreakOnAllocFailed )
{
DebugBreak();
}
#endif
}
return ((LPVOID) pAligned);
}
VOID
WINAPI
ServerFree(
LPVOID p
)
{
if (p != NULL)
{
LPVOID pOrig = (LPVOID) *(((LPDWORD) p) - 2);
LocalFree (pOrig);
}
#if DBG
else
{
DBGOUT((4,"----- ServerFree: ptr = NULL!"));
}
#endif
}
BOOL
PASCAL
MyDuplicateHandle(
HANDLE hSource,
LPHANDLE phTarget
)
{
if (!DuplicateHandle(
TapiGlobals.hProcess,
hSource,
TapiGlobals.hProcess,
phTarget,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
DBGOUT((
1,
"MyDuplicateHandle: DuplicateHandle failed, err=%ld",
GetLastError()
));
return FALSE;
}
return TRUE;
}
HANDLE
MyCreateMutex(
void
)
{
HANDLE hMutex;
hMutex = CreateMutex(
NULL, // no security attrs
FALSE, // unowned
NULL // unnamed
);
return (hMutex);
}
BOOL
WaitForMutex(
HANDLE hMutex,
HANDLE *phMutex,
BOOL *pbDupedMutex,
LPVOID pWidget,
DWORD dwKey,
DWORD dwTimeout
)
{
DWORD dwResult;
//
// First try to instantaneously grab the specified mutex. We wrap
// this in a critical section and preface it with widget validation
// to make sure that we don't happen grab a pWidget->hMutex right
// after it is released and right before it is closed by some other
// thread "T2" in a DestroyWidget routine. This scenario could cause
// deadlock, since there could be thread "T3" waiting on this mutex
// (or a dup'd handle), and this thread "T1" would have no way to
// release the mutex (the handle having been subsequently closed by
// thread "T2" calling DestroyWidget above).
//
EnterCriticalSection (&gSafeMutexCritSec);
if (pWidget)
{
try
{
if (IsBadPtrKey (pWidget, dwKey))
{
LeaveCriticalSection (&gSafeMutexCritSec);
return FALSE;
}
}
myexcept
{
LeaveCriticalSection (&gSafeMutexCritSec);
return FALSE;
}
}
switch ((dwResult = WaitForSingleObject (hMutex, 0)))
{
case WAIT_OBJECT_0:
LeaveCriticalSection (&gSafeMutexCritSec);
*phMutex = hMutex;
*pbDupedMutex = FALSE;
return TRUE;
//case WAIT_ABANDONED:
//assert: no calling thread should ever be terminated!
default:
break;
}
LeaveCriticalSection (&gSafeMutexCritSec);
//
// If here we failed to instantaneously grab the specified mutex.
// Try to dup it, and then wait on the dup'd handle. We do this so
// that each thread which grabs a mutex is guaranteed to have a valid
// handle to release at some future time, as the original hMutex might
// get closed by some other thread calling a DestroyWidget routine.
//
if (!DuplicateHandle(
TapiGlobals.hProcess,
hMutex,
TapiGlobals.hProcess,
phMutex,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
return FALSE;
}
WaitForMutex_wait:
switch ((dwResult = WaitForSingleObject (*phMutex, dwTimeout)))
{
case WAIT_OBJECT_0:
*pbDupedMutex = TRUE;
return TRUE;
case WAIT_TIMEOUT:
try
{
if (*((LPDWORD) pWidget) == dwKey)
{
goto WaitForMutex_wait;
}
}
myexcept
{
// just fall thru without blowing up
}
CloseHandle (*phMutex);
break;
//case WAIT_ABANDONED:
//assert: no calling thread should ever be terminated!
default:
break;
}
return FALSE;
}
void
MyReleaseMutex(
HANDLE hMutex,
BOOL bCloseMutex
)
{
if (hMutex)
{
ReleaseMutex (hMutex);
if (bCloseMutex)
{
CloseHandle (hMutex);
}
}
}
void
CALLBACK
CompletionProcSP(
DWORD dwRequestID,
LONG lResult
)
{
#if DBG
{
char szResult[32];
DBGOUT((
3,
"CompletionProc: enter, dwReqID=x%x, lResult=%s",
dwRequestID,
MapResultCodeToText (lResult, szResult)
));
}
#endif
((PASYNCREQUESTINFO) dwRequestID)->lResult = lResult;
QueueSPEvent ((PSPEVENT) dwRequestID);
}
void
PASCAL
CompletionProc(
PASYNCREQUESTINFO pAsyncRequestInfo,
LONG lResult
)
{
// DWORD dwNumBytesWritten;
ASYNCEVENTMSG msg;
//
// Validate the async request structure pointer
//
try
{
if (IsBadPtrKey (pAsyncRequestInfo, TASYNC_KEY))
{
return;
}
pAsyncRequestInfo->dwKey = INVAL_KEY;
}
myexcept
{
return;
}
//
// Init the msg we'll send to client
//
msg.dwTotalSize = sizeof (ASYNCEVENTMSG);
msg.pInitData = pAsyncRequestInfo->pInitData;
msg.pfnPostProcessProc = pAsyncRequestInfo->pfnClientPostProcessProc;
msg.hDevice = 0;
msg.dwMsg = (pAsyncRequestInfo->bLineFunc ?
LINE_REPLY : PHONE_REPLY);
msg.dwCallbackInst = pAsyncRequestInfo->dwCallbackInst;
msg.dwParam1 = pAsyncRequestInfo->dwRequestID;
msg.dwParam2 = lResult;
msg.dwParam3 = 0;
//
// If there's a post processing proc call it. Note that ppprocs can
// create their own msg to pass, so we need to check for this case.
// Finally, write the msg to the client's event buffer.
//
if (pAsyncRequestInfo->pfnPostProcess)
{
LPVOID pBuf = NULL;
(*pAsyncRequestInfo->pfnPostProcess)(pAsyncRequestInfo, &msg, &pBuf);
WriteEventBuffer (pAsyncRequestInfo->ptClient, (pBuf ? pBuf : &msg));
if (pBuf)
{
ServerFree (pBuf);
}
}
else
{
WriteEventBuffer (pAsyncRequestInfo->ptClient, &msg);
}
// caller will free pAsyncRequestInfo
}
void
WriteEventBuffer(
PTCLIENT ptClient,
PASYNCEVENTMSG pMsg
)
{
BOOL bCloseMutex;
HANDLE hMutex;
try
{
hMutex = (ptClient->hProcess == (HANDLE) 0xffffffff ?
NULL : ptClient->hMutex);
if (ptClient->dwKey != TCLIENT_KEY)
{
return;
}
}
myexcept
{
return;
}
if (hMutex)
{
//
// Local client
//
if (WaitForMutex(
ptClient->hEventBufferMutex,
&hMutex,
&bCloseMutex,
ptClient,
TCLIENT_KEY,
INFINITE
))
{
if (ptClient->dwKey == TCLIENT_KEY)
{
DWORD dwMoveSize = pMsg->dwTotalSize, dwMoveSizeWrapped = 0;
//
// Check to see if we need to grow the event buffer
//
if (dwMoveSize > (ptClient->dwEventBufferTotalSize -
ptClient->dwEventBufferUsedSize))
{
DWORD dwMoveSize2, dwMoveSizeWrapped2,
dwNewEventBufferTotalSize;
LPBYTE pNewEventBuffer;
dwNewEventBufferTotalSize =
ptClient->dwEventBufferTotalSize + dwMoveSize + 512;
if (!(pNewEventBuffer = ServerAlloc(
dwNewEventBufferTotalSize
)))
{
// BUGBUG WriteEventBuffer: attempt grow event buf failed
}
if (ptClient->dwEventBufferUsedSize != 0)
{
if (ptClient->pDataIn > ptClient->pDataOut)
{
dwMoveSize2 = (DWORD) (ptClient->pDataIn -
ptClient->pDataOut);
dwMoveSizeWrapped2 = 0;
}
else
{
dwMoveSize2 = (DWORD) ((ptClient->pEventBuffer +
ptClient->dwEventBufferTotalSize) -
ptClient->pDataOut);
dwMoveSizeWrapped2 = (DWORD) (ptClient->pDataIn -
ptClient->pEventBuffer);
}
CopyMemory(
pNewEventBuffer,
ptClient->pDataOut,
dwMoveSize2
);
if (dwMoveSizeWrapped2)
{
CopyMemory(
pNewEventBuffer + dwMoveSize2,
ptClient->pEventBuffer,
dwMoveSizeWrapped2
);
}
ptClient->pDataIn = pNewEventBuffer + dwMoveSize2 +
dwMoveSizeWrapped2;
}
else
{
ptClient->pDataIn = pNewEventBuffer;
}
ServerFree (ptClient->pEventBuffer);
ptClient->pDataOut =
ptClient->pEventBuffer = pNewEventBuffer;
ptClient->dwEventBufferTotalSize =
dwNewEventBufferTotalSize;
}
if (ptClient->pDataIn >= ptClient->pDataOut)
{
DWORD dwFreeSize = ptClient->dwEventBufferTotalSize -
(ptClient->pDataIn - ptClient->pEventBuffer);
if (dwMoveSize > dwFreeSize)
{
dwMoveSizeWrapped = dwMoveSize - dwFreeSize;
dwMoveSize = dwFreeSize;
}
}
CopyMemory (ptClient->pDataIn, (LPBYTE) pMsg, dwMoveSize);
if (dwMoveSizeWrapped != 0)
{
CopyMemory(
ptClient->pEventBuffer,
((LPBYTE) pMsg) + dwMoveSize,
dwMoveSizeWrapped
);
ptClient->pDataIn = ptClient->pEventBuffer + dwMoveSizeWrapped;
}
else
{
ptClient->pDataIn += dwMoveSize;
if (ptClient->pDataIn >= (ptClient->pEventBuffer +
ptClient->dwEventBufferTotalSize))
{
ptClient->pDataIn = ptClient->pEventBuffer;
}
}
ptClient->dwEventBufferUsedSize += pMsg->dwTotalSize;
SetEvent (ptClient->hValidEventBufferDataEvent);
// DBGOUT((
// 3,
// "WriteEventBuffer: bytesWritten=x%x (local)",
// dwMoveSize
// ));
}
MyReleaseMutex (hMutex, bCloseMutex);
}
}
else
{
//
// Remote client
//
//
// !!! Note the overloading of the pMsg->dwCallbackInst field here
// (the EventNotificationThread needs to know which client the
// msg is destined for), which is preferable to adding yet
// another 4 bytes to the ASYNCEVENTMSG struct. Remotesp never
// looks at the dwCallbackInst field in msgs anyways.
//
pMsg->dwCallbackInst = (DWORD) ptClient;
EnterCriticalSection (&gRemoteCliEventBufCritSec);
{
DWORD dwMoveSize = pMsg->dwTotalSize, dwMoveSizeWrapped = 0;
//
// Check to see if we need to grow the event buffer
//
if (dwMoveSize >
(gEventNotificationThreadParams.dwEventBufferTotalSize -
gEventNotificationThreadParams.dwEventBufferUsedSize))
{
DWORD dwMoveSize2, dwMoveSizeWrapped2,
dwNewEventBufferTotalSize;
LPBYTE pNewEventBuffer;
dwNewEventBufferTotalSize = dwMoveSize + 512 +
gEventNotificationThreadParams.dwEventBufferTotalSize;
if (!(pNewEventBuffer = ServerAlloc(
dwNewEventBufferTotalSize
)))
{
// BUGBUG WriteEventBuffer: attempt grow event buf failed
}
if (gEventNotificationThreadParams.pDataIn >
gEventNotificationThreadParams.pDataOut)
{
dwMoveSize2 = (DWORD)
(gEventNotificationThreadParams.pDataIn -
gEventNotificationThreadParams.pDataOut);
dwMoveSizeWrapped2 = 0;
}
else
{
dwMoveSize2 = (DWORD)
((gEventNotificationThreadParams.pEventBuffer +
gEventNotificationThreadParams.dwEventBufferTotalSize)
- gEventNotificationThreadParams.pDataOut);
dwMoveSizeWrapped2 = (DWORD)
(gEventNotificationThreadParams.pDataIn -
gEventNotificationThreadParams.pEventBuffer);
}
CopyMemory(
pNewEventBuffer,
gEventNotificationThreadParams.pDataOut,
dwMoveSize2
);
if (dwMoveSizeWrapped2)
{
CopyMemory(
pNewEventBuffer + dwMoveSize2,
gEventNotificationThreadParams.pEventBuffer,
dwMoveSizeWrapped2
);
}
ServerFree (gEventNotificationThreadParams.pEventBuffer);
gEventNotificationThreadParams.pDataIn = pNewEventBuffer +
dwMoveSize2 + dwMoveSizeWrapped2;
gEventNotificationThreadParams.pDataOut =
gEventNotificationThreadParams.pEventBuffer = pNewEventBuffer;
gEventNotificationThreadParams.dwEventBufferTotalSize =
dwNewEventBufferTotalSize;
}
if (gEventNotificationThreadParams.pDataIn >=
gEventNotificationThreadParams.pDataOut)
{
DWORD dwFreeSize;
dwFreeSize =
gEventNotificationThreadParams.dwEventBufferTotalSize -
(gEventNotificationThreadParams.pDataIn -
gEventNotificationThreadParams.pEventBuffer);
if (dwMoveSize > dwFreeSize)
{
dwMoveSizeWrapped = dwMoveSize - dwFreeSize;
dwMoveSize = dwFreeSize;
}
}
CopyMemory(
gEventNotificationThreadParams.pDataIn,
(LPBYTE) pMsg,
dwMoveSize
);
if (dwMoveSizeWrapped != 0)
{
CopyMemory(
gEventNotificationThreadParams.pEventBuffer,
((LPBYTE) pMsg) + dwMoveSize,
dwMoveSizeWrapped
);
gEventNotificationThreadParams.pDataIn =
gEventNotificationThreadParams.pEventBuffer +
dwMoveSizeWrapped;
}
else
{
gEventNotificationThreadParams.pDataIn += dwMoveSize;
if (gEventNotificationThreadParams.pDataIn >=
(gEventNotificationThreadParams.pEventBuffer +
gEventNotificationThreadParams.dwEventBufferTotalSize))
{
gEventNotificationThreadParams.pDataIn =
gEventNotificationThreadParams.pEventBuffer;
}
}
gEventNotificationThreadParams.dwEventBufferUsedSize +=
pMsg->dwTotalSize;
SetEvent (gEventNotificationThreadParams.hEvent);
// DBGOUT((
// 3,
// "WriteEventBuffer: bytesWritten=x%x (remote)",
// dwMoveSize
// ));
}
LeaveCriticalSection (&gRemoteCliEventBufCritSec);
}
}
LONG
AddLine(
PTPROVIDER ptProvider,
DWORD dwDeviceID,
BOOL bInit
)
{
DWORD dwSPIVersion;
HANDLE hMutex = NULL;
PTLINELOOKUPTABLE pLookup;
//
// First try to negotiate an SPI ver for this device, and alloc the
// necessary resources
//
if (CallSP4(
ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION],
"lineNegotiateTSPIVersion",
SP_FUNC_SYNC,
dwDeviceID,
TAPI_VERSION1_0,
TAPI_VERSION_CURRENT,
(DWORD) &dwSPIVersion
) != 0)
{
//
// Device failed version negotiation, so we'll keep the id around
// (since the id's for the devices that follow have already been
// assigned) but mark this device as bad
//
ptProvider = NULL;
}
else if (!(hMutex = MyCreateMutex ()))
{
DBGOUT((
1,
"AddLine: MyCreateMutex failed, err=%d",
GetLastError()
));
return LINEERR_OPERATIONFAILED;
}
//
// Now walk the lookup table to find a free entry
//
pLookup = TapiGlobals.pLineLookup;
while (pLookup->pNext)
{
pLookup = pLookup->pNext;
}
if (pLookup->dwNumUsedEntries == pLookup->dwNumTotalEntries)
{
PTLINELOOKUPTABLE pNewLookup;
if (!(pNewLookup = ServerAlloc(
sizeof (TLINELOOKUPTABLE) +
(2 * pLookup->dwNumTotalEntries - 1) *
sizeof (TLINELOOKUPENTRY)
)))
{
return LINEERR_NOMEM;
}
pNewLookup->dwNumTotalEntries = 2 * pLookup->dwNumTotalEntries;
//
// If we're initializing we want to put everything in one big table
//
if (bInit)
{
pNewLookup->dwNumUsedEntries = pLookup->dwNumTotalEntries;
CopyMemory(
pNewLookup->aEntries,
pLookup->aEntries,
pLookup->dwNumTotalEntries * sizeof (TLINELOOKUPENTRY)
);
ServerFree (pLookup);
TapiGlobals.pLineLookup = pNewLookup;
}
pLookup = pNewLookup;
}
//
// Initialize the entry
//
{
DWORD index = pLookup->dwNumUsedEntries;
pLookup->aEntries[index].dwSPIVersion = dwSPIVersion;
pLookup->aEntries[index].hMutex = hMutex;
pLookup->aEntries[index].ptProvider = ptProvider;
if (ptProvider &&
lstrcmpiW(ptProvider->szFileName, L"kmddsp.tsp") == 0)
{
pLookup->aEntries[index].bRemote = TRUE;
}
}
pLookup->dwNumUsedEntries++;
return 0;
}
LONG
AddPhone(
PTPROVIDER ptProvider,
DWORD dwDeviceID,
BOOL bInit
)
{
DWORD dwSPIVersion;
HANDLE hMutex = NULL;
PTPHONELOOKUPTABLE pLookup;
//
// First try to negotiate an SPI ver for this device, and alloc the
// necessary resources
//
if (CallSP4(
ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION],
"phoneNegotiateTSPIVersion",
SP_FUNC_SYNC,
dwDeviceID,
TAPI_VERSION1_0,
TAPI_VERSION_CURRENT,
(DWORD) &dwSPIVersion
) != 0)
{
//
// Device failed version negotiation, so we'll keep the id around
// (since the id's for the devices that follow have already been
// assigned) but mark this device as bad
//
ptProvider = NULL;
}
else if (!(hMutex = MyCreateMutex ()))
{
DBGOUT((
1,
"AddPhone: MyCreateMutex failed, err=%d",
GetLastError()
));
return PHONEERR_OPERATIONFAILED;
}
//
// Now walk the lookup table to find a free entry
//
pLookup = TapiGlobals.pPhoneLookup;
while (pLookup->pNext)
{
pLookup = pLookup->pNext;
}
if (pLookup->dwNumUsedEntries == pLookup->dwNumTotalEntries)
{
PTPHONELOOKUPTABLE pNewLookup;
if (!(pNewLookup = ServerAlloc(
sizeof (TPHONELOOKUPTABLE) +
(2 * pLookup->dwNumTotalEntries - 1) *
sizeof (TPHONELOOKUPENTRY)
)))
{
return PHONEERR_NOMEM;
}
pNewLookup->dwNumTotalEntries = 2 * pLookup->dwNumTotalEntries;
//
// If we're initializing we want to put everything in one big table
//
if (bInit)
{
pNewLookup->dwNumUsedEntries = pLookup->dwNumTotalEntries;
CopyMemory(
pNewLookup->aEntries,
pLookup->aEntries,
pLookup->dwNumTotalEntries * sizeof (TPHONELOOKUPENTRY)
);
ServerFree (pLookup);
TapiGlobals.pPhoneLookup = pNewLookup;
}
pLookup = pNewLookup;
}
//
// Initialize the entry
//
{
DWORD index = pLookup->dwNumUsedEntries;
pLookup->aEntries[index].dwSPIVersion = dwSPIVersion;
pLookup->aEntries[index].hMutex = hMutex;
pLookup->aEntries[index].ptProvider = ptProvider;
}
pLookup->dwNumUsedEntries++;
return 0;
}
void
PASCAL
GetPriorityList(
HKEY hKeyHandoffPriorities,
WCHAR *pszListName,
WCHAR **ppszPriorityList
)
{
LONG lResult;
DWORD dwType, dwNumBytes;
*ppszPriorityList = NULL;
if ((lResult = RegQueryValueExW(
hKeyHandoffPriorities,
pszListName,
NULL,
&dwType,
NULL,
&dwNumBytes
)) == ERROR_SUCCESS &&
(dwNumBytes != 0))
{
WCHAR *pszPriorityList = ServerAlloc ( dwNumBytes + sizeof(WCHAR));
// need an extra WCHAR for the extra '"'
if (pszPriorityList)
{
pszPriorityList[0] = '"';
if ((lResult = RegQueryValueExW(
hKeyHandoffPriorities,
pszListName,
NULL,
&dwType,
(LPBYTE)(pszPriorityList + 1),
&dwNumBytes
)) == ERROR_SUCCESS)
{
CharUpperW (pszPriorityList);
*ppszPriorityList = pszPriorityList;
DBGOUT((3, "PriList: %ls=%ls", pszListName, pszPriorityList));
}
}
else
{
//
// Don't bother with the failure to alloc a priority list
// (list defaults to NULL anyway), we'll deal with a lack
// of memory at a later time
//
*ppszPriorityList = NULL;
}
}
else
{
*ppszPriorityList = NULL;
DBGOUT((3, "PriList: %ls=NULL", pszListName));
}
}
LONG
ServerInit(
void
)
{
UINT uiNumProviders, i, j;
HKEY hKeyTelephony, hKeyProviders;
DWORD dwDataSize, dwDataType;
//
// Initialize the globals
//
TapiGlobals.dwAsyncRequestID = 1;
TapiGlobals.ptProviders = NULL;
TapiGlobals.pLineLookup = (PTLINELOOKUPTABLE) ServerAlloc(
sizeof (TLINELOOKUPTABLE) +
(DEF_NUM_LOOKUP_ENTRIES - 1) * sizeof (TLINELOOKUPENTRY)
);
TapiGlobals.pLineLookup->dwNumTotalEntries = DEF_NUM_LOOKUP_ENTRIES;
TapiGlobals.pPhoneLookup = (PTPHONELOOKUPTABLE) ServerAlloc(
sizeof (TPHONELOOKUPTABLE) +
(DEF_NUM_LOOKUP_ENTRIES - 1) * sizeof (TPHONELOOKUPENTRY)
);
TapiGlobals.pPhoneLookup->dwNumTotalEntries = DEF_NUM_LOOKUP_ENTRIES;
gbQueueSPEvents = TRUE;
//
// Determine number of providers
//
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_ALL_ACCESS,
&hKeyTelephony
);
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
);
dwDataSize = sizeof(uiNumProviders);
uiNumProviders = 0;
RegQueryValueEx(
hKeyProviders,
gszNumProviders,
0,
&dwDataType,
(LPBYTE) &uiNumProviders,
&dwDataSize
);
DBGOUT((3, "ServerInit: NumProviders=%d", uiNumProviders));
//
// Load & init the providers
//
for (i = 0; i < uiNumProviders; i++)
{
#define FILENAME_SIZE 128
WCHAR szFilename[FILENAME_SIZE];
WCHAR buf[32];
LONG lResult;
DWORD dwNumLines, dwNumPhones, dwPermanentProviderID;
PTPROVIDER ptProvider;
wsprintfW(buf, L"%ls%d", gszProviderIDW, i);
dwDataSize = sizeof(dwPermanentProviderID);
dwPermanentProviderID = 0;
RegQueryValueExW(
hKeyProviders,
buf, //"ProviderID#"
0,
&dwDataType,
(LPBYTE) &dwPermanentProviderID,
&dwDataSize
);
//
// Back to the main section
//
dwDataSize = FILENAME_SIZE;
wsprintfW (buf, L"%ls%d", gszProviderFilenameW, i);
RegQueryValueExW(
hKeyProviders,
buf, // "ProviderFilename#"
0,
&dwDataType,
(LPBYTE) szFilename,
&dwDataSize
);
szFilename[dwDataSize] = '\0';
DBGOUT((3, "ServerInit: ProviderFilename=%ls", szFilename));
if (!(ptProvider = (PTPROVIDER) ServerAlloc(
sizeof(TPROVIDER) + ((lstrlenW(szFilename) + 1) * sizeof(WCHAR))
)))
{
// BUGBUG ServerInit: handle tprovider alloc failure
break;
}
if (!(ptProvider->hDll = LoadLibraryW (szFilename)))
{
DBGOUT((
3,
"ServerInit: LoadLibraryW(%ls) failed, err=x%x",
szFilename,
GetLastError()
));
ServerFree (ptProvider);
continue;
}
lstrcpyW(ptProvider->szFileName, szFilename);
//
// Get all the TSPI proc addrs
//
for (j = 0; gaszTSPIFuncNames[j]; j++)
{
ptProvider->apfn[j] = (TSPIPROC) GetProcAddress(
ptProvider->hDll,
(LPCSTR) gaszTSPIFuncNames[j]
);
}
//
// A real quick check to see if a couple of required entrypoints
// are exported
//
if (!ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION] ||
!ptProvider->apfn[SP_PROVIDERENUMDEVICES] ||
!ptProvider->apfn[SP_PROVIDERINIT] ||
!ptProvider->apfn[SP_PROVIDERSHUTDOWN]
)
{
goto ServerInit_validateEntrypoints;
}
//
// Do global provider version negotiation
//
lResult = CallSP4(
ptProvider->apfn[SP_LINENEGOTIATETSPIVERSION],
"lineNegotiateTSPIVersion",
SP_FUNC_SYNC,
INITIALIZE_NEGOTIATION,
TAPI_VERSION1_0,
TAPI_VERSION_CURRENT,
(DWORD) &ptProvider->dwSPIVersion
);
if (lResult != 0)
{
FreeLibrary (ptProvider->hDll);
ServerFree (ptProvider);
continue;
}
//
// Try to enum the devices if provider supports it, otherwise
// try grabbing the num lines & phones from ProviderN section
//
dwNumLines = dwNumPhones = 0;
lResult = CallSP6(
ptProvider->apfn[SP_PROVIDERENUMDEVICES],
"providerEnumDevices",
SP_FUNC_SYNC,
dwPermanentProviderID,
(DWORD) &dwNumLines,
(DWORD) &dwNumPhones,
(DWORD) ptProvider,
(DWORD) LineEventProcSP,
(DWORD) PhoneEventProcSP
);
//
// Init the provider
//
// !!! HACK ALERT: for kmddsp pass ptr's to dwNumXxxs
//
DBGOUT((3, "ServerInit: %ls: Calling TSPI_providerInit", szFilename));
if (lstrcmpiW(szFilename, L"kmddsp.tsp") == 0)
{
dwNumLines = (DWORD) &dwNumLines;
dwNumPhones = (DWORD) &dwNumPhones;
}
else if (lstrcmpiW(szFilename, L"remotesp.tsp") == 0)
{
pRemoteSP = ptProvider;
}
lResult = CallSP8(
ptProvider->apfn[SP_PROVIDERINIT],
"providerInit",
SP_FUNC_SYNC,
(DWORD) ptProvider->dwSPIVersion,
(DWORD) dwPermanentProviderID,
(DWORD) TapiGlobals.pLineLookup->dwNumUsedEntries,
(DWORD) TapiGlobals.pPhoneLookup->dwNumUsedEntries,
(DWORD) dwNumLines,
(DWORD) dwNumPhones,
(DWORD) CompletionProcSP,
(DWORD) &ptProvider->dwTSPIOptions
);
if (lResult != 0)
{
DBGOUT((
1,
"ServerInit: %ls: failed TSPI_providerInit [x%x]" \
" - skipping it...",
szFilename,
lResult
));
FreeLibrary (ptProvider->hDll);
ServerFree (ptProvider);
continue;
}
DBGOUT((
3,
"ServerInit: %ls init'd, dwNumLines=%ld, dwNumPhones=%ld",
szFilename,
dwNumLines,
dwNumPhones
));
//
// Now that we know if we have line and/or phone devs check for
// the required entry points
//
ServerInit_validateEntrypoints:
{
DWORD adwRequiredEntrypointIndices[] =
{
SP_LINENEGOTIATETSPIVERSION,
SP_PROVIDERINIT,
SP_PROVIDERSHUTDOWN,
SP_PHONENEGOTIATETSPIVERSION,
0xffffffff
};
BOOL bRequiredEntrypointsExported = TRUE;
//
// If this provider doesn't support any phone devices then
// it isn't required to export phone funcs
//
if (dwNumPhones == 0)
{
adwRequiredEntrypointIndices[3] = 0xffffffff;
}
//DBGOUT((0, " ptProvider=0x%08lx", ptProvider));
for (j = 0;
adwRequiredEntrypointIndices[j] != 0xffffffff;
j++
)
{
if (ptProvider->apfn[adwRequiredEntrypointIndices[j]]
== (TSPIPROC) NULL)
{
DBGOUT((
1,
"ServerInit: %ls: can't init, func ordinal #%ld " \
"not exported",
szFilename,
// TSPI_PROC_BASE + j
500 + j
));
bRequiredEntrypointsExported = FALSE;
}
}
if (bRequiredEntrypointsExported == FALSE)
{
FreeLibrary (ptProvider->hDll);
ServerFree (ptProvider);
continue;
}
}
//
// Do version negotiation on each device & add them to lookup lists
//
{
DWORD dwDeviceIDBase;
dwDeviceIDBase = TapiGlobals.pLineLookup->dwNumUsedEntries;
for (j = dwDeviceIDBase; j < (dwDeviceIDBase + dwNumLines); j++)
{
if (AddLine (ptProvider, j, TRUE))
{
// BUGBUG ServerInit: handle AddLine failure
}
}
dwDeviceIDBase = TapiGlobals.pPhoneLookup->dwNumUsedEntries;
for (j = dwDeviceIDBase; j < (dwDeviceIDBase + dwNumPhones); j++)
{
if (AddPhone (ptProvider, j, TRUE))
{
// BUGBUG ServerInit: handle AddPhone failure
}
}
}
//
//
//
ptProvider->hMutex = MyCreateMutex();
ptProvider->dwPermanentProviderID = dwPermanentProviderID;
//
// Add provider to head of list, mark as valid
//
ptProvider->pNext = TapiGlobals.ptProviders;
TapiGlobals.ptProviders = ptProvider;
ptProvider->dwKey = TPROVIDER_KEY;
}
RegCloseKey (hKeyProviders);
RegCloseKey (hKeyTelephony);
//
// Save lookup lists & num devices
//
TapiGlobals.dwNumLines = TapiGlobals.pLineLookup->dwNumUsedEntries;
TapiGlobals.dwNumPhones = TapiGlobals.pPhoneLookup->dwNumUsedEntries;
// init perf stuff
PerfBlock.dwLines = TapiGlobals.dwNumLines;
PerfBlock.dwPhones = TapiGlobals.dwNumPhones;
return 0;
}
void
PASCAL
SetPriorityList(
HKEY hKeyHandoffPriorities,
WCHAR *pszListName,
WCHAR *pszPriorityList
)
{
if (pszPriorityList == NULL)
{
//
// There is no pri list for this media mode or ReqXxxCall,
// so delete any existing value from the registry
//
RegDeleteValueW (hKeyHandoffPriorities, pszListName);
}
else
{
//
// Add the pri list to the registry (note that we don't
// add the preceding '"')
//
RegSetValueExW(
hKeyHandoffPriorities,
pszListName,
0,
REG_SZ,
(LPBYTE)(pszPriorityList + 1),
lstrlenW (pszPriorityList) * sizeof (WCHAR)
);
}
}
LONG
ServerShutdown(
void
)
{
DWORD i;
PTPROVIDER ptProvider;
//
// Reset the flag that says it's ok to queue sp events, & then wait
// for the SPEventHandlerThread to clean up the SP event queue.
//
EnterCriticalSection (&gSPEventQueueCritSec);
gbQueueSPEvents = FALSE;
LeaveCriticalSection (&gSPEventQueueCritSec);
while (gpOldestSPEvent != NULL)
{
Sleep (0);
}
//
// For each provider call the shutdown proc & then unload
//
ptProvider = TapiGlobals.ptProviders;
while (ptProvider)
{
PTPROVIDER ptNextProvider = ptProvider->pNext;
LONG lResult;
lResult = CallSP2(
ptProvider->apfn[SP_PROVIDERSHUTDOWN],
"providerShutdown",
SP_FUNC_SYNC,
ptProvider->dwSPIVersion,
ptProvider->dwPermanentProviderID
);
FreeLibrary (ptProvider->hDll);
CloseHandle (ptProvider->hMutex);
ServerFree (ptProvider);
ptProvider = ptNextProvider;
}
//
// Clean up lookup tables
//
while (TapiGlobals.pLineLookup)
{
PTLINELOOKUPTABLE pLookup = TapiGlobals.pLineLookup;
for (i = 0; i < pLookup->dwNumUsedEntries; i++)
{
CloseHandle (pLookup->aEntries[i].hMutex);
}
TapiGlobals.pLineLookup = pLookup->pNext;
ServerFree (pLookup);
}
while (TapiGlobals.pPhoneLookup)
{
PTPHONELOOKUPTABLE pLookup = TapiGlobals.pPhoneLookup;
for (i = 0; i < pLookup->dwNumUsedEntries; i++)
{
CloseHandle (pLookup->aEntries[i].hMutex);
}
TapiGlobals.pPhoneLookup = pLookup->pNext;
ServerFree (pLookup);
}
{
WCHAR szPerfNumLines[] = L"Perf1";
WCHAR szPerfNumPhones[] = L"Perf2";
HKEY hKeyTelephony;
DWORD dwValue;
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyTelephony,
0,
KEY_ALL_ACCESS,
&hKeyTelephony
);
dwValue = TapiGlobals.dwNumLines + 'PERF';
RegSetValueExW(
hKeyTelephony,
szPerfNumLines,
0,
REG_DWORD,
(LPBYTE)&dwValue,
sizeof(DWORD)
);
dwValue = TapiGlobals.dwNumPhones + 'PERF';
RegSetValueExW(
hKeyTelephony,
szPerfNumPhones,
0,
REG_DWORD,
(LPBYTE)&dwValue,
sizeof(DWORD)
);
RegCloseKey(hKeyTelephony);
}
//
// Reset globals
//
TapiGlobals.bReinit = FALSE;
return 0;
}
void
WINAPI
GetAsyncEvents(
PGETEVENTS_PARAMS pParams,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
DWORD dwMoveSize, dwMoveSizeWrapped;
PTCLIENT ptClient = pParams->ptClient;
// DBGOUT((3, "GetAsyncEvents: enter (TID=%d)", GetCurrentThreadId()));
DBGOUT((91, "M ebfused:x%lx pEvtBuf: 0x%08lx pDataOut:0x%08lx pDataIn:0x%08lx",
ptClient->dwEventBufferUsedSize,
ptClient->pEventBuffer,
ptClient->pDataOut,
ptClient->pDataIn ));
//
// Copy data from ptClient's event buffer
//
// An optimization to be made is to alert client (via dwNeededSize)
// that it might want to alloc a larger buffer when msg traffic is
// real high
//
WaitForSingleObject (ptClient->hEventBufferMutex, INFINITE);
if (ptClient->dwEventBufferUsedSize == 0)
{
ResetEvent (ptClient->hValidEventBufferDataEvent);
pParams->dwNeededBufferSize =
pParams->dwUsedBufferSize = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG);
goto GetAsyncEvents_releaseMutex;
}
if (ptClient->pDataOut < ptClient->pDataIn)
{
dwMoveSize = ptClient->pDataIn - ptClient->pDataOut;
dwMoveSizeWrapped = 0;
}
else
{
dwMoveSize = ptClient->dwEventBufferTotalSize -
(ptClient->pDataOut - ptClient->pEventBuffer);
dwMoveSizeWrapped = ptClient->pDataIn - ptClient->pEventBuffer;
}
if (ptClient->dwEventBufferUsedSize < pParams->dwTotalBufferSize)
{
//
// If here the size of the queued event data is less than the
// client buffer size, so we can just blast the bits into the
// client buffer & return. Also make sure to reset the "events
// pending" event
//
CopyMemory (pDataBuf, ptClient->pDataOut, dwMoveSize);
if (dwMoveSizeWrapped)
{
CopyMemory(
pDataBuf + dwMoveSize,
ptClient->pEventBuffer,
dwMoveSizeWrapped
);
}
ptClient->dwEventBufferUsedSize = 0;
ptClient->pDataOut = ptClient->pDataIn;
ResetEvent (ptClient->hValidEventBufferDataEvent);
pParams->dwNeededBufferSize =
pParams->dwUsedBufferSize = dwMoveSize + dwMoveSizeWrapped;
// DBGOUT((3, "GetAsyncEvents: usedSize=x%x", pParams->dwUsedBufferSize));
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwUsedBufferSize;
}
else
{
//
// If here the size of the queued event data exceeds that
// of the client buffer. Since our events aren't all the
// same size we need to copy them over one by one, making
// sure we don't overflow the client buffer. Don't reset
// the "events pending" event, so async events thread will
// call us again as soon as it's done processing messages
// in the buffer.
//
//
DWORD dwBytesLeftInClientBuffer = pParams->dwTotalBufferSize,
dwDataOffset = 0, dwDataOffsetWrapped = 0;
DWORD dwTotalMoveSize = dwMoveSize;
while (1)
{
DWORD dwMsgSize = ((PASYNCEVENTMSG)
(ptClient->pDataOut + dwDataOffset))->dwTotalSize;
//DBGOUT((1, " L evntbuf:x%lx DataOff=x%lx DataOffWrap=x%lx msgsize=x%lx bytesleft=x%lx movesiz=x%lx",
// ptClient->pEventBuffer,
// dwDataOffset,
// dwDataOffsetWrapped,
// dwMsgSize,
// dwBytesLeftInClientBuffer,
// dwMoveSize ));
if (dwMsgSize > dwBytesLeftInClientBuffer)
{
if ((pParams->dwUsedBufferSize = dwDataOffset) != 0)
{
ptClient->dwEventBufferUsedSize -= dwDataOffset;
ptClient->pDataOut += dwDataOffset;
pParams->dwNeededBufferSize = dwDataOffset;
}
else
{
//BUGBUG? Should this be out one level? bjm 4/2/96
//
// Special case: the 1st msg is bigger than the entire
// buffer
//
pParams->dwNeededBufferSize = dwMsgSize + 0x100;
}
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pParams->dwUsedBufferSize;
goto GetAsyncEvents_releaseMutex;
}
dwBytesLeftInClientBuffer -= dwMsgSize;
if (dwMsgSize <= dwMoveSize)
{
//
// Msg isn't wrapped, a single copy will do
//
CopyMemory(
pDataBuf + dwDataOffset,
ptClient->pDataOut + dwDataOffset,
dwMsgSize
);
//
// Check to see if the msg ran to the end of the buffer,
// & break to the wrapped data code if so
//
if ((dwDataOffset += dwMsgSize) >= dwTotalMoveSize)
{
ptClient->pDataOut = ptClient->pEventBuffer;
break;
}
}
else
{
//
// This msg is wrapped. We need to do two copies, then
// break out of this loop to the wrapped data code
//
CopyMemory(
pDataBuf + dwDataOffset,
ptClient->pDataOut + dwDataOffset,
dwMoveSize
);
dwDataOffset += dwMoveSize;
CopyMemory(
pDataBuf + dwDataOffset,
ptClient->pEventBuffer,
dwMsgSize - dwMoveSize
);
dwDataOffset += ( dwMsgSize - dwMoveSize);
ptClient->pDataOut = ptClient->pEventBuffer +
(dwMsgSize - dwMoveSize);
break;
}
dwMoveSize -= dwMsgSize;
}
//DBGOUT((1, " L evbufused:x%lx pEvtBuf: x%lx pDataOut:x%lx pDataIn:x%lx",
// ptClient->dwEventBufferUsedSize,
// ptClient->pEventBuffer,
// ptClient->pDataOut,
// ptClient->pDataIn ));
while (1)
{
DWORD dwMsgSize = ((PASYNCEVENTMSG) (ptClient->pDataOut +
dwDataOffsetWrapped))->dwTotalSize;
//ServerFree( ServerAlloc( 0x10000 ) );
//
//DBGOUT((1, " S evntbuf:x%lx DataOff=x%lx DataOffWrap=x%lx msgsize=x%lx bytesleft=x%lx",
// ptClient->pEventBuffer,
// dwDataOffset,
// dwDataOffsetWrapped,
// dwMsgSize,
// dwBytesLeftInClientBuffer));
if (
(dwMsgSize > dwBytesLeftInClientBuffer)
// ||
// (dwMsgSize == 0)
)
{
ptClient->dwEventBufferUsedSize -=
(dwDataOffset ); // + dwDataOffsetWrapped);
ptClient->pDataOut += dwDataOffsetWrapped;
pParams->dwNeededBufferSize =
pParams->dwUsedBufferSize = dwDataOffset +
0; // dwDataOffsetWrapped;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pParams->dwUsedBufferSize;
//DBGOUT((1, " S evbufused:x%lx pEvtBuf: x%lx pDataOut:x%lx pDataIn:x%lx",
// ptClient->dwEventBufferUsedSize,
// ptClient->pEventBuffer,
// ptClient->pDataOut,
// ptClient->pDataIn ));
goto GetAsyncEvents_releaseMutex;
}
//
// Msg isn't wrapped, a single copy will do
//
CopyMemory(
pDataBuf + dwDataOffset,
ptClient->pDataOut + dwDataOffsetWrapped,
dwMsgSize
);
dwDataOffset += dwMsgSize;
dwDataOffsetWrapped += dwMsgSize;
dwBytesLeftInClientBuffer -= dwMsgSize;
}
}
GetAsyncEvents_releaseMutex:
ReleaseMutex (ptClient->hEventBufferMutex);
// DBGOUT((3, "GetAsyncEvents: exit (TID=%d)", GetCurrentThreadId()));
}
void
WINAPI
GetUIDllName(
PGETUIDLLNAME_PARAMS pParams,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LONG lResult = 0;
TSPIPROC pfnTSPI_providerUIIdentify = (TSPIPROC) NULL;
PTAPIDIALOGINSTANCE ptDlgInst = (PTAPIDIALOGINSTANCE) NULL;
switch (pParams->dwObjectType)
{
case TUISPIDLL_OBJECT_LINEID:
{
PTLINELOOKUPENTRY pLookupEntry =
GetLineLookupEntry (pParams->dwObjectID);
if (!pLookupEntry)
{
lResult = (TapiGlobals.dwNumLineInits == 0 ?
LINEERR_UNINITIALIZED : LINEERR_BADDEVICEID);
}
else if (!pLookupEntry->ptProvider || pLookupEntry->bRemoved)
{
lResult = LINEERR_NODEVICE;
}
else if (!(pfnTSPI_providerUIIdentify =
pLookupEntry->ptProvider->apfn[SP_PROVIDERUIIDENTIFY]))
{
lResult = LINEERR_OPERATIONUNAVAIL;
}
break;
}
case TUISPIDLL_OBJECT_PHONEID:
{
PTPHONELOOKUPENTRY pLookupEntry =
GetPhoneLookupEntry (pParams->dwObjectID);
if (!pLookupEntry)
{
lResult = (TapiGlobals.dwNumPhoneInits == 0 ?
PHONEERR_UNINITIALIZED : PHONEERR_BADDEVICEID);
}
else if (!pLookupEntry->ptProvider || pLookupEntry->bRemoved)
{
lResult = PHONEERR_NODEVICE;
}
else if (!(pfnTSPI_providerUIIdentify =
pLookupEntry->ptProvider->apfn[SP_PROVIDERUIIDENTIFY]))
{
lResult = PHONEERR_OPERATIONUNAVAIL;
}
break;
}
case TUISPIDLL_OBJECT_PROVIDERID:
DBGOUT((1, "Looking for provider..."));
if (!(ptDlgInst = ServerAlloc (sizeof (TAPIDIALOGINSTANCE))))
{
lResult = LINEERR_NOMEM;
goto GetUIDllName_return;
}
if (pParams->dwProviderFilenameOffset == TAPI_NO_DATA)
{
//
// This is a providerConfig or -Remove request. Loop thru the
// list of installed providers, trying to find one with a
// matching PPID.
//
int i, iNumProviders;
WCHAR szProviderXxxN[32];
HKEY hKeyProviders;
DWORD dwDataSize;
DWORD dwDataType;
DWORD dwTemp;
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
) != ERROR_SUCCESS)
{
DBGOUT((
1,
"RegOpenKeyEx(/Providers) failed, err=%d",
GetLastError()
));
ServerFree (ptDlgInst);
lResult = LINEERR_OPERATIONFAILED;
goto GetUIDllName_return;
}
dwDataSize = sizeof(iNumProviders);
iNumProviders = 0;
RegQueryValueEx(
hKeyProviders,
gszNumProviders,
0,
&dwDataType,
(LPBYTE) &iNumProviders,
&dwDataSize
);
for (i = 0; i < iNumProviders; i++)
{
wsprintfW(szProviderXxxN, L"%ls%d", gszProviderIDW, i);
dwDataSize = sizeof(dwTemp);
dwTemp = 0;
RegQueryValueExW(
hKeyProviders,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE)&dwTemp,
&dwDataSize
);
if (dwTemp == pParams->dwObjectID)
{
//
// We found the provider, try to load it & get ptrs
// to the relevant funcs
//
WCHAR szProviderFilename[MAX_PATH];
wsprintfW(szProviderXxxN, L"%ls%d", gszProviderFilenameW, i);
dwDataSize = MAX_PATH;
RegQueryValueExW(
hKeyProviders,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE)szProviderFilename,
&dwDataSize
);
// szProviderFilename[dwDataSize] = '\0';
if (!(ptDlgInst->hTsp = LoadLibraryW(szProviderFilename)))
{
DBGOUT((
1,
"LoadLibrary('%ls') failed - err=%d",
szProviderFilename,
GetLastError()
));
lResult = LINEERR_OPERATIONFAILED;
goto clean_up_dlg_inst;
}
if (!(pfnTSPI_providerUIIdentify = GetProcAddress(
ptDlgInst->hTsp,
(LPCSTR) gaszTSPIFuncNames[SP_PROVIDERUIIDENTIFY]
)))
{
DBGOUT((
1,
"GetProcAddress(TSPI_providerUIIdentify) " \
"on [%ls] failed, err=%d",
szProviderFilename,
GetLastError()
));
lResult = LINEERR_OPERATIONUNAVAIL;
goto clean_up_dlg_inst;
}
ptDlgInst->pfnTSPI_providerGenericDialogData =
GetProcAddress(
ptDlgInst->hTsp,
(LPCSTR) gaszTSPIFuncNames[SP_PROVIDERGENERICDIALOGDATA]
);
ptDlgInst->dwPermanentProviderID = pParams->dwObjectID;
ptDlgInst->bRemoveProvider = pParams->bRemoveProvider;
break;
}
}
if (i == iNumProviders)
{
DBGOUT((1, "Ran out of list..."));
lResult = LINEERR_INVALPARAM;
}
RegCloseKey (hKeyProviders);
}
else
{
//
// This is a providerInstall request. Try to load the provider
// and get ptrs to the relevant funcs, then retrieve & increment
// the next provider ID value in the ini file (careful to wrap
// next PPID at 64K-1).
//
WCHAR *pszProviderFilename;
DWORD dwNameLength;
HKEY hKeyProviders;
DWORD dwDataSize;
DWORD dwDataType;
DWORD dwTemp;
pszProviderFilename = (PWSTR)(pDataBuf + pParams->dwProviderFilenameOffset);
if (!(ptDlgInst->hTsp = LoadLibraryW(pszProviderFilename)))
{
DBGOUT((
1,
"LoadLibrary('%ls') failed err=%d",
pszProviderFilename,
GetLastError()
));
lResult = LINEERR_OPERATIONFAILED;
goto clean_up_dlg_inst;
}
if (!(pfnTSPI_providerUIIdentify = GetProcAddress(
ptDlgInst->hTsp,
(LPCSTR) gaszTSPIFuncNames[SP_PROVIDERUIIDENTIFY]
)))
{
lResult = LINEERR_OPERATIONUNAVAIL;
goto clean_up_dlg_inst;
}
dwNameLength = (lstrlenW(pszProviderFilename) + 1) * sizeof(WCHAR);
if (!(ptDlgInst->pszProviderFilename = ServerAlloc (dwNameLength)))
{
lResult = LINEERR_NOMEM;
goto clean_up_dlg_inst;
}
CopyMemory(
ptDlgInst->pszProviderFilename,
pszProviderFilename,
dwNameLength
);
ptDlgInst->pfnTSPI_providerGenericDialogData = GetProcAddress(
ptDlgInst->hTsp,
(LPCSTR) gaszTSPIFuncNames[SP_PROVIDERGENERICDIALOGDATA]
);
// BUGBUG needs mutex
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
);
dwDataSize = sizeof (DWORD);
ptDlgInst->dwPermanentProviderID = 1;
RegQueryValueEx(
hKeyProviders,
gszNextProviderID,
0,
&dwDataType,
(LPBYTE) &(ptDlgInst->dwPermanentProviderID),
&dwDataSize
);
pParams->dwObjectID = ptDlgInst->dwPermanentProviderID;
//bjm 2/16 dwTemp = (ptDlgInst->dwPermanentProviderID & 0xffff0000) ?
//bjm 2/16 1 : (ptDlgInst->dwPermanentProviderID + 1);
dwTemp = ((ptDlgInst->dwPermanentProviderID+1) & 0xffff0000) ?
1 : (ptDlgInst->dwPermanentProviderID + 1);
RegSetValueEx(
hKeyProviders,
gszNextProviderID,
0,
REG_DWORD,
(LPBYTE) &dwTemp,
sizeof(DWORD)
);
RegCloseKey (hKeyProviders);
}
break;
}
if (pfnTSPI_providerUIIdentify)
{
if ((lResult = CallSP1(
pfnTSPI_providerUIIdentify,
"providerUIIdentify",
SP_FUNC_SYNC,
(DWORD) pDataBuf
)) == 0)
{
pParams->dwUIDllNameOffset = 0;
pParams->dwUIDllNameSize = (lstrlenW((PWSTR)pDataBuf) + 1)*sizeof(WCHAR);
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pParams->dwUIDllNameSize;
if (ptDlgInst)
{
ptDlgInst->dwKey = TDLGINST_KEY;
// BUGBUG mutex
if ((ptDlgInst->pNext =
pParams->ptClient->pProviderXxxDlgInsts))
{
ptDlgInst->pNext->pPrev = ptDlgInst;
}
pParams->ptClient->pProviderXxxDlgInsts = ptDlgInst;
pParams->htDlgInst = (HTAPIDIALOGINSTANCE) ptDlgInst;
}
}
else if (ptDlgInst)
{
clean_up_dlg_inst:
if (ptDlgInst->hTsp)
{
FreeLibrary (ptDlgInst->hTsp);
}
if (ptDlgInst->pszProviderFilename)
{
ServerFree (ptDlgInst->pszProviderFilename);
}
ServerFree (ptDlgInst);
}
}
GetUIDllName_return:
pParams->lResult = lResult;
}
void
WINAPI
TUISPIDLLCallback(
PUIDLLCALLBACK_PARAMS pParams,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
LONG lResult;
DWORD dwObjectID = pParams->dwObjectID;
TSPIPROC pfnTSPI_providerGenericDialogData = NULL;
switch (pParams->dwObjectType)
{
case TUISPIDLL_OBJECT_LINEID:
{
PTLINELOOKUPENTRY pLine = GetLineLookupEntry (pParams->dwObjectID);
if (!pLine)
{
lResult = LINEERR_INVALPARAM;
}
else if (!pLine->ptProvider)
{
lResult = LINEERR_OPERATIONFAILED;
}
else
{
pfnTSPI_providerGenericDialogData =
pLine->ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
}
break;
}
case TUISPIDLL_OBJECT_PHONEID:
{
PTPHONELOOKUPENTRY pPhone = GetPhoneLookupEntry (pParams->dwObjectID);
if (!pPhone)
{
lResult = LINEERR_INVALPARAM;
}
else if (!pPhone->ptProvider)
{
lResult = LINEERR_OPERATIONFAILED;
}
else
{
pfnTSPI_providerGenericDialogData =
pPhone->ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
}
break;
}
case TUISPIDLL_OBJECT_PROVIDERID:
{
PTAPIDIALOGINSTANCE ptDlgInst =
pParams->ptClient->pProviderXxxDlgInsts;
while (ptDlgInst)
{
if (pParams->dwObjectID == ptDlgInst->dwPermanentProviderID)
{
pfnTSPI_providerGenericDialogData =
ptDlgInst->pfnTSPI_providerGenericDialogData;
break;
}
ptDlgInst = ptDlgInst->pNext;
}
break;
}
case TUISPIDLL_OBJECT_DIALOGINSTANCE:
try
{
dwObjectID = (DWORD)
((PTAPIDIALOGINSTANCE)pParams->dwObjectID)->hdDlgInst;
pfnTSPI_providerGenericDialogData =
((PTAPIDIALOGINSTANCE) pParams->dwObjectID)->
ptProvider->apfn[SP_PROVIDERGENERICDIALOGDATA];
}
myexcept
{
// just fall thru
}
break;
}
if (pfnTSPI_providerGenericDialogData)
{
if ((lResult = CallSP4(
pfnTSPI_providerGenericDialogData,
"providerGenericDialogData",
SP_FUNC_SYNC,
(DWORD) dwObjectID,
(DWORD) pParams->dwObjectType,
(DWORD) pDataBuf + pParams->dwParamsInOffset,
(DWORD) pParams->dwParamsInSize
)) == 0)
{
pParams->dwParamsOutOffset = 0;
pParams->dwParamsOutSize = pParams->dwParamsInSize;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
pParams->dwParamsOutSize;
}
}
else
{
lResult = LINEERR_OPERATIONFAILED;
}
pParams->lResult = lResult;
}
void
WINAPI
FreeDialogInstance(
PFREEDIALOGINSTANCE_PARAMS pParams,
LPBYTE pDataBuf,
LPDWORD pdwNumBytesReturned
)
{
HKEY hKeyProviders;
DWORD dwDataSize;
DWORD dwDataType;
DWORD dwTemp;
PTCLIENT ptClient = pParams->ptClient;
PTAPIDIALOGINSTANCE ptDlgInst = (PTAPIDIALOGINSTANCE) pParams->htDlgInst;
DBGOUT((3, "FreeDialogInstance: enter, pDlgInst=x%x", ptDlgInst));
// BUGBUG FreeDialogInstance: needs mutex on tClient access
try
{
if (IsBadPtrKey (ptDlgInst, TDLGINST_KEY))
{
pParams->lResult = LINEERR_OPERATIONFAILED;
}
else
{
ptDlgInst->dwKey = INVAL_KEY;
}
}
myexcept
{
pParams->lResult = LINEERR_OPERATIONFAILED;
}
if (pParams->lResult)
{
return;
}
if (ptDlgInst->hTsp)
{
//
// This dlg inst was a client doing a providerConfig, -Install, or
// -Remove
//
if (ptDlgInst->pszProviderFilename)
{
if (pParams->lUIDllResult == 0)
{
//
// Successful provider install
//
DWORD iNumProviders;
WCHAR szProviderXxxN[32];
CHAR szProviderXxxNA[32];
// BUGBUG mutex
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
);
dwDataSize = sizeof(iNumProviders);
iNumProviders = 0;
RegQueryValueEx(
hKeyProviders,
gszNumProviders,
0,
&dwDataType,
(LPBYTE) &iNumProviders,
&dwDataSize
);
wsprintf(
szProviderXxxNA,
"%ls%d",
gszProviderIDW,
iNumProviders
);
RegSetValueEx(
hKeyProviders,
szProviderXxxNA,
0,
REG_DWORD,
(LPBYTE) &ptDlgInst->dwPermanentProviderID,
sizeof(DWORD)
);
wsprintfW(
szProviderXxxN,
L"%ls%d",
gszProviderFilenameW,
iNumProviders
);
RegSetValueExW(
hKeyProviders,
szProviderXxxN,
0,
REG_SZ,
(LPBYTE) ptDlgInst->pszProviderFilename,
(lstrlenW((PWSTR)ptDlgInst->pszProviderFilename) + 1)*sizeof(WCHAR)
);
iNumProviders++;
RegSetValueEx(
hKeyProviders,
gszNumProviders,
0,
REG_DWORD,
(LPBYTE) &iNumProviders,
sizeof(DWORD)
);
RegCloseKey( hKeyProviders );
// BUGBUG if tapisrv is init'd then load the provider, &
// send CREATE msgs for all it's devices
}
else
{
//
// Unsuccessful provider install. See if we can decrement
// NextProviderID to free up the unused ID.
//
DWORD iNextProviderID;
// BUGBUG mutex
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
);
dwDataSize = sizeof(iNextProviderID);
iNextProviderID = 0;
RegQueryValueEx(
hKeyProviders,
gszNextProviderID,
0,
&dwDataType,
(LPBYTE)&iNextProviderID,
&dwDataSize
);
if ((ptDlgInst->dwPermanentProviderID + 1) == iNextProviderID)
{
RegSetValueEx(
hKeyProviders,
gszNextProviderID,
0,
REG_DWORD,
(LPBYTE) &(ptDlgInst->dwPermanentProviderID),
sizeof(DWORD)
);
}
RegCloseKey (hKeyProviders);
}
ServerFree (ptDlgInst->pszProviderFilename);
}
else if (ptDlgInst->bRemoveProvider)
{
if (pParams->lUIDllResult == 0)
{
//
// Successful provider remove. Find the index of the
// provider in the list, then move all the providers
// that follow up a notch.
//
DWORD iNumProviders, i;
WCHAR *buf, szProviderXxxN[32];
// BUGBUG mutex
RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
gszRegKeyProviders,
0,
KEY_ALL_ACCESS,
&hKeyProviders
);
dwDataSize = sizeof(iNumProviders);
iNumProviders = 0;
RegQueryValueEx(
hKeyProviders,
gszNumProviders,
0,
&dwDataType,
(LPBYTE) &iNumProviders,
&dwDataSize
);
for (i = 0; i < iNumProviders; i++)
{
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderIDW, i);
dwDataSize = sizeof(dwTemp);
dwTemp = 0;
RegQueryValueExW(
hKeyProviders,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE) &dwTemp,
&dwDataSize
);
if (dwTemp == ptDlgInst->dwPermanentProviderID)
{
break;
}
}
buf = ServerAlloc (MAX_PATH);
for (; i < (iNumProviders - 1); i++)
{
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderIDW, i + 1);
dwDataSize = MAX_PATH;
RegQueryValueExW(
hKeyProviders,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE) buf,
&dwDataSize
);
buf[dwDataSize] = '\0';
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderIDW, i);
RegSetValueExW(
hKeyProviders,
szProviderXxxN,
0,
REG_DWORD,
(LPBYTE) buf,
sizeof (DWORD)
);
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderFilenameW,i+1);
dwDataSize = MAX_PATH;
RegQueryValueExW(
hKeyProviders,
szProviderXxxN,
0,
&dwDataType,
(LPBYTE) buf,
&dwDataSize
);
buf[dwDataSize] = '\0';
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderFilenameW, i);
RegSetValueExW(
hKeyProviders,
szProviderXxxN,
0,
REG_SZ,
(LPBYTE) buf,
(lstrlenW(buf) + 1) * sizeof(WCHAR)
);
}
//
// Remove the last ProviderID# & ProviderFilename# entries
//
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderIDW, i);
RegDeleteValueW (hKeyProviders, szProviderXxxN);
wsprintfW (szProviderXxxN, L"%ls%d", gszProviderFilenameW, i);
RegDeleteValueW (hKeyProviders, szProviderXxxN);
//
// Decrement the total num providers to load
//
iNumProviders--;
RegSetValueEx(
hKeyProviders,
gszNumProviders,
0,
REG_DWORD,
(LPBYTE)&iNumProviders,
sizeof(DWORD)
);
// BUGBUG providerRemove- if tapi init'd shutdown provider
}
else
{
//
// Unsuccessful provider remove, nothing to do
//
}
}
else
{
//
// Nothing to do for providerConfig (success or fail)
//
}
FreeLibrary (ptDlgInst->hTsp);
pParams->lResult = pParams->lUIDllResult;
}
else
{
//
// The was a provider-initiated dlg inst, so tell
// the provider to free it's inst
//
CallSP1(
ptDlgInst->ptProvider->apfn[SP_PROVIDERFREEDIALOGINSTANCE],
"providerFreeDialogInstance",
SP_FUNC_SYNC,
(DWORD) ptDlgInst->hdDlgInst
);
}
//
// Remove the dialog instance from the tClient's list & then free it
//
if (ptDlgInst->pNext)
{
ptDlgInst->pNext->pPrev = ptDlgInst->pPrev;
}
if (ptDlgInst->pPrev)
{
ptDlgInst->pPrev->pNext = ptDlgInst->pNext;
}
else if (ptDlgInst->hTsp)
{
pParams->ptClient->pProviderXxxDlgInsts = ptDlgInst->pNext;
}
else
{
pParams->ptClient->pGenericDlgInsts = ptDlgInst->pNext;
}
ServerFree (ptDlgInst);
}
#pragma warning (default:4028)
#if DBG
char szBeforeSync[] = "Calling TSPI_%s";
char szBeforeAsync[] = "Calling TSPI_%s, dwReqID=x%x";
char szAfter[] = "TSPI_%s result=%s";
VOID
DbgPrt(
IN DWORD dwDbgLevel,
IN PUCHAR lpszFormat,
IN ...
)
/*++
Routine Description:
Formats the incoming debug message & calls DbgPrint
Arguments:
DbgLevel - level of message verboseness
DbgMessage - printf-style format string, followed by appropriate
list of arguments
Return Value:
--*/
{
if (dwDbgLevel <= gdwDebugLevel)
{
char buf[1024] = "TAPISRV: ";
va_list ap;
va_start(ap, lpszFormat);
wvsprintf(
&buf[9],
lpszFormat,
ap
);
lstrcat(buf, "\n");
OutputDebugStringA (buf);
va_end(ap);
}
return;
}
char *aszLineErrors[] =
{
NULL,
"ALLOCATED",
"BADDEVICEID",
"BEARERMODEUNAVAIL",
"inval err value (0x80000004)", // 0x80000004 isn't valid err code
"CALLUNAVAIL",
"COMPLETIONOVERRUN",
"CONFERENCEFULL",
"DIALBILLING",
"DIALDIALTONE",
"DIALPROMPT",
"DIALQUIET",
"INCOMPATIBLEAPIVERSION",
"INCOMPATIBLEEXTVERSION",
"INIFILECORRUPT",
"INUSE",
"INVALADDRESS", // 0x80000010
"INVALADDRESSID",
"INVALADDRESSMODE",
"INVALADDRESSSTATE",
"INVALAPPHANDLE",
"INVALAPPNAME",
"INVALBEARERMODE",
"INVALCALLCOMPLMODE",
"INVALCALLHANDLE",
"INVALCALLPARAMS",
"INVALCALLPRIVILEGE",
"INVALCALLSELECT",
"INVALCALLSTATE",
"INVALCALLSTATELIST",
"INVALCARD",
"INVALCOMPLETIONID",
"INVALCONFCALLHANDLE", // 0x80000020
"INVALCONSULTCALLHANDLE",
"INVALCOUNTRYCODE",
"INVALDEVICECLASS",
"INVALDEVICEHANDLE",
"INVALDIALPARAMS",
"INVALDIGITLIST",
"INVALDIGITMODE",
"INVALDIGITS",
"INVALEXTVERSION",
"INVALGROUPID",
"INVALLINEHANDLE",
"INVALLINESTATE",
"INVALLOCATION",
"INVALMEDIALIST",
"INVALMEDIAMODE",
"INVALMESSAGEID", // 0x80000030
"inval err value (0x80000031)", // 0x80000031 isn't valid err code
"INVALPARAM",
"INVALPARKID",
"INVALPARKMODE",
"INVALPOINTER",
"INVALPRIVSELECT",
"INVALRATE",
"INVALREQUESTMODE",
"INVALTERMINALID",
"INVALTERMINALMODE",
"INVALTIMEOUT",
"INVALTONE",
"INVALTONELIST",
"INVALTONEMODE",
"INVALTRANSFERMODE",
"LINEMAPPERFAILED", // 0x80000040
"NOCONFERENCE",
"NODEVICE",
"NODRIVER",
"NOMEM",
"NOREQUEST",
"NOTOWNER",
"NOTREGISTERED",
"OPERATIONFAILED",
"OPERATIONUNAVAIL",
"RATEUNAVAIL",
"RESOURCEUNAVAIL",
"REQUESTOVERRUN",
"STRUCTURETOOSMALL",
"TARGETNOTFOUND",
"TARGETSELF",
"UNINITIALIZED", // 0x80000050
"USERUSERINFOTOOBIG",
"REINIT",
"ADDRESSBLOCKED",
"BILLINGREJECTED",
"INVALFEATURE",
"NOMULTIPLEINSTANCE",
"INVALAGENTID",
"INVALAGENTGROUP",
"INVALPASSWORD",
"INVALAGENTSTATE",
"INVALAGENTACTIVITY",
"DIALVOICEDETECT"
};
char *aszPhoneErrors[] =
{
"SUCCESS",
"ALLOCATED",
"BADDEVICEID",
"INCOMPATIBLEAPIVERSION",
"INCOMPATIBLEEXTVERSION",
"INIFILECORRUPT",
"INUSE",
"INVALAPPHANDLE",
"INVALAPPNAME",
"INVALBUTTONLAMPID",
"INVALBUTTONMODE",
"INVALBUTTONSTATE",
"INVALDATAID",
"INVALDEVICECLASS",
"INVALEXTVERSION",
"INVALHOOKSWITCHDEV",
"INVALHOOKSWITCHMODE", // 0x90000010
"INVALLAMPMODE",
"INVALPARAM",
"INVALPHONEHANDLE",
"INVALPHONESTATE",
"INVALPOINTER",
"INVALPRIVILEGE",
"INVALRINGMODE",
"NODEVICE",
"NODRIVER",
"NOMEM",
"NOTOWNER",
"OPERATIONFAILED",
"OPERATIONUNAVAIL",
"inval err value (0x9000001e)", // 0x9000001e isn't valid err code
"RESOURCEUNAVAIL",
"REQUESTOVERRUN", // 0x90000020
"STRUCTURETOOSMALL",
"UNINITIALIZED",
"REINIT"
};
char *aszTapiErrors[] =
{
"SUCCESS",
"DROPPED",
"NOREQUESTRECIPIENT",
"REQUESTQUEUEFULL",
"INVALDESTADDRESS",
"INVALWINDOWHANDLE",
"INVALDEVICECLASS",
"INVALDEVICEID",
"DEVICECLASSUNAVAIL",
"DEVICEIDUNAVAIL",
"DEVICEINUSE",
"DESTBUSY",
"DESTNOANSWER",
"DESTUNAVAIL",
"UNKNOWNWINHANDLE",
"UNKNOWNREQUESTID",
"REQUESTFAILED",
"REQUESTCANCELLED",
"INVALPOINTER"
};
char *
PASCAL
MapResultCodeToText(
LONG lResult,
char *pszResult
)
{
if (lResult == 0)
{
wsprintf (pszResult, "SUCCESS");
}
else if (lResult > 0)
{
wsprintf (pszResult, "x%x (completing async)", lResult);
}
else if (((DWORD) lResult) <= LINEERR_DIALVOICEDETECT)
{
lResult &= 0x0fffffff;
wsprintf (pszResult, "LINEERR_%s", aszLineErrors[lResult]);
}
else if (((DWORD) lResult) <= PHONEERR_REINIT)
{
if (((DWORD) lResult) >= PHONEERR_ALLOCATED)
{
lResult &= 0x0fffffff;
wsprintf (pszResult, "PHONEERR_%s", aszPhoneErrors[lResult]);
}
else
{
goto MapResultCodeToText_badErrorCode;
}
}
else if (((DWORD) lResult) <= ((DWORD) TAPIERR_DROPPED) &&
((DWORD) lResult) >= ((DWORD) TAPIERR_INVALPOINTER))
{
lResult = ~lResult + 1;
wsprintf (pszResult, "TAPIERR_%s", aszTapiErrors[lResult]);
}
else
{
MapResultCodeToText_badErrorCode:
wsprintf (pszResult, "inval error value (x%x)");
}
return pszResult;
}
VOID
PASCAL
ValidateSyncSPResult(
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
LONG lResult
)
{
char szResult[32];
DBGOUT((
3,
szAfter,
lpszFuncName,
MapResultCodeToText (lResult, szResult)
));
if (dwFlags & SP_FUNC_ASYNC)
{
assert (lResult != 0);
if (lResult > 0)
{
assert ((DWORD) lResult == dwArg1);
}
}
else
{
assert (lResult <= 0);
}
}
LONG
WINAPI
CallSP1(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1
)
{
LONG lResult;
DBGOUT((3, szBeforeSync, lpszFuncName));
lResult = (*pfn)(dwArg1);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP2(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP3(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2, dwArg3);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP4(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2, dwArg3, dwArg4);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP5(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2, dwArg3, dwArg4, dwArg5);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP6(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5,
DWORD dwArg6
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2, dwArg3, dwArg4, dwArg5, dwArg6);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP7(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5,
DWORD dwArg6,
DWORD dwArg7
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(dwArg1, dwArg2, dwArg3, dwArg4, dwArg5, dwArg6, dwArg7);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP8(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5,
DWORD dwArg6,
DWORD dwArg7,
DWORD dwArg8
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(
dwArg1,
dwArg2,
dwArg3,
dwArg4,
dwArg5,
dwArg6,
dwArg7,
dwArg8
);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP9(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5,
DWORD dwArg6,
DWORD dwArg7,
DWORD dwArg8,
DWORD dwArg9
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(
dwArg1,
dwArg2,
dwArg3,
dwArg4,
dwArg5,
dwArg6,
dwArg7,
dwArg8,
dwArg9
);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
LONG
WINAPI
CallSP12(
TSPIPROC pfn,
LPCSTR lpszFuncName,
DWORD dwFlags,
DWORD dwArg1,
DWORD dwArg2,
DWORD dwArg3,
DWORD dwArg4,
DWORD dwArg5,
DWORD dwArg6,
DWORD dwArg7,
DWORD dwArg8,
DWORD dwArg9,
DWORD dwArg10,
DWORD dwArg11,
DWORD dwArg12
)
{
LONG lResult;
if (dwFlags & SP_FUNC_ASYNC)
{
DBGOUT((3, szBeforeAsync, lpszFuncName, dwArg1));
}
else
{
DBGOUT((3, szBeforeSync, lpszFuncName));
}
lResult = (*pfn)(
dwArg1,
dwArg2,
dwArg3,
dwArg4,
dwArg5,
dwArg6,
dwArg7,
dwArg8,
dwArg9,
dwArg10,
dwArg11,
dwArg12
);
ValidateSyncSPResult (lpszFuncName, dwFlags, dwArg1, lResult);
return lResult;
}
#endif // DBG
/*************************************************************************\
* BOOL InitPerf()
*
* Initialize global performance data
*
\**************************************************************************/
BOOL InitPerf()
{
FillMemory(&PerfBlock,
sizeof(PerfBlock),
0);
return(TRUE);
}