mirror of https://github.com/tongzx/nt5src
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.
6529 lines
180 KiB
6529 lines
180 KiB
/*++ BUILD Version: 0000 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 1995-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
phone.c
|
|
|
|
Abstract:
|
|
|
|
Src module for tapi server phone funcs
|
|
|
|
Author:
|
|
|
|
Dan Knudson (DanKn) 01-Apr-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "windows.h"
|
|
#include "assert.h"
|
|
#include "tapi.h"
|
|
#include "tspi.h"
|
|
#include "utils.h"
|
|
#include "client.h"
|
|
#include "server.h"
|
|
#include "phone.h"
|
|
#include "tapihndl.h"
|
|
#include "private.h"
|
|
|
|
#include "string.h"
|
|
|
|
extern TAPIGLOBALS TapiGlobals;
|
|
|
|
extern PTPROVIDER pRemoteSP;
|
|
|
|
extern CRITICAL_SECTION gSafeMutexCritSec;
|
|
|
|
extern HANDLE ghHandleTable;
|
|
|
|
extern BOOL gbQueueSPEvents;
|
|
extern BOOL gbNTServer;
|
|
extern BOOL gbServerInited;
|
|
|
|
|
|
|
|
#if DBG
|
|
char *
|
|
PASCAL
|
|
MapResultCodeToText(
|
|
LONG lResult,
|
|
char *pszResult
|
|
);
|
|
#endif
|
|
|
|
void
|
|
DestroytPhoneClient(
|
|
HPHONE hPhone
|
|
);
|
|
|
|
BOOL
|
|
IsAPIVersionInRange(
|
|
DWORD dwAPIVersion,
|
|
DWORD dwSPIVersion
|
|
);
|
|
|
|
LONG
|
|
InitTapiStruct(
|
|
LPVOID pTapiStruct,
|
|
DWORD dwTotalSize,
|
|
DWORD dwFixedSize,
|
|
BOOL bZeroInit
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendMsgToPhoneClients(
|
|
PTPHONE ptPhone,
|
|
PTPHONECLIENT ptPhoneClienttoExclude,
|
|
DWORD Msg,
|
|
DWORD Param1,
|
|
DWORD Param2,
|
|
DWORD Param3
|
|
);
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivetPhoneAccess(
|
|
PTPHONE ptPhone,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendReinitMsgToAllXxxApps(
|
|
void
|
|
);
|
|
|
|
PTCLIENT
|
|
PASCAL
|
|
WaitForExclusiveClientAccess(
|
|
PTCLIENT ptClient
|
|
);
|
|
|
|
void
|
|
CALLBACK
|
|
CompletionProcSP(
|
|
DWORD dwRequestID,
|
|
LONG lResult
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendAMsgToAllPhoneApps(
|
|
DWORD dwWantVersion,
|
|
DWORD dwMsg,
|
|
DWORD Param1,
|
|
DWORD Param2,
|
|
DWORD Param3
|
|
);
|
|
|
|
BOOL
|
|
GetPhonePermanentIdFromDeviceID(
|
|
PTCLIENT ptClient,
|
|
DWORD dwDeviceID,
|
|
LPTAPIPERMANENTID pID
|
|
);
|
|
|
|
LONG
|
|
InitializeClient(
|
|
PTCLIENT ptClient
|
|
);
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneClientListFromPhone(
|
|
PTPHONE ptPhone,
|
|
PTPOINTERLIST *ppList
|
|
);
|
|
|
|
BOOL
|
|
IsBadStructParam(
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
DWORD dwXxxOffset
|
|
);
|
|
|
|
void
|
|
CALLBACK
|
|
PhoneEventProcSP(
|
|
HTAPIPHONE htPhone,
|
|
DWORD dwMsg,
|
|
ULONG_PTR Param1,
|
|
ULONG_PTR Param2,
|
|
ULONG_PTR Param3
|
|
);
|
|
|
|
LONG
|
|
GetPermPhoneIDAndInsertInTable(
|
|
PTPROVIDER ptProvider,
|
|
DWORD dwDeviceID,
|
|
DWORD dwSPIVersion
|
|
);
|
|
|
|
LONG
|
|
AppendNewDeviceInfo (
|
|
BOOL bLine,
|
|
DWORD dwDeviceID
|
|
);
|
|
|
|
LONG
|
|
RemoveDeviceInfoEntry (
|
|
BOOL bLine,
|
|
DWORD dwDeviceID
|
|
);
|
|
|
|
LONG
|
|
PASCAL
|
|
GetClientList(
|
|
BOOL bAdminOnly,
|
|
PTPOINTERLIST *ppList
|
|
);
|
|
|
|
PTPHONELOOKUPENTRY
|
|
GetPhoneLookupEntry(
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
DWORD dwDeviceIDBase = 0;
|
|
PTPHONELOOKUPTABLE pLookupTable = TapiGlobals.pPhoneLookup;
|
|
|
|
|
|
if (dwDeviceID >= TapiGlobals.dwNumPhones)
|
|
{
|
|
return ((PTPHONELOOKUPENTRY) NULL);
|
|
}
|
|
|
|
while (pLookupTable)
|
|
{
|
|
if (dwDeviceID < pLookupTable->dwNumTotalEntries)
|
|
{
|
|
return (pLookupTable->aEntries + dwDeviceID);
|
|
}
|
|
|
|
dwDeviceID -= pLookupTable->dwNumTotalEntries;
|
|
|
|
pLookupTable = pLookupTable->pNext;
|
|
}
|
|
|
|
return ((PTPHONELOOKUPENTRY) NULL);
|
|
}
|
|
|
|
|
|
LONG
|
|
GetPhoneVersions(
|
|
HPHONE hPhone,
|
|
LPDWORD lpdwAPIVersion,
|
|
LPDWORD lpdwSPIVersion
|
|
)
|
|
{
|
|
LONG lResult;
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
if ((ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
hPhone,
|
|
TPHONECLIENT_KEY
|
|
)))
|
|
{
|
|
*lpdwAPIVersion = ptPhoneClient->dwAPIVersion;
|
|
|
|
try
|
|
{
|
|
*lpdwSPIVersion = ptPhoneClient->ptPhone->dwSPIVersion;
|
|
|
|
lResult = (ptPhoneClient->dwKey == TPHONECLIENT_KEY ?
|
|
0 : PHONEERR_INVALPHONEHANDLE);
|
|
}
|
|
myexcept
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, hPhone, 1);
|
|
}
|
|
else
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PASCAL
|
|
IsValidPhoneExtVersion(
|
|
DWORD dwDeviceID,
|
|
DWORD dwExtVersion
|
|
)
|
|
{
|
|
BOOL bResult;
|
|
PTPHONE ptPhone;
|
|
PTPROVIDER ptProvider;
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
|
|
|
|
if (dwExtVersion == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(pLookupEntry = GetPhoneLookupEntry (dwDeviceID)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ptPhone = pLookupEntry->ptPhone;
|
|
|
|
if (ptPhone)
|
|
{
|
|
try
|
|
{
|
|
if (ptPhone->dwExtVersionCount)
|
|
{
|
|
bResult = (dwExtVersion == ptPhone->dwExtVersion ?
|
|
TRUE : FALSE);
|
|
|
|
if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
goto IsValidPhoneExtVersion_return;
|
|
}
|
|
}
|
|
|
|
}
|
|
myexcept
|
|
{
|
|
//
|
|
// if here the phone was closed, just drop thru to the code below
|
|
//
|
|
}
|
|
}
|
|
|
|
ptProvider = pLookupEntry->ptProvider;
|
|
|
|
if (ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION])
|
|
{
|
|
LONG lResult;
|
|
DWORD dwNegotiatedExtVersion;
|
|
|
|
|
|
lResult = CallSP5(
|
|
ptProvider->apfn[SP_PHONENEGOTIATEEXTVERSION],
|
|
"phoneNegotiateExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) pLookupEntry->dwSPIVersion,
|
|
(DWORD) dwExtVersion,
|
|
(DWORD) dwExtVersion,
|
|
(ULONG_PTR) &dwNegotiatedExtVersion
|
|
);
|
|
|
|
bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE);
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
IsValidPhoneExtVersion_return:
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
PTPHONEAPP
|
|
PASCAL
|
|
IsValidPhoneApp(
|
|
HPHONEAPP hPhoneApp,
|
|
PTCLIENT ptClient
|
|
)
|
|
{
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
if ((ptPhoneApp = ReferenceObject(
|
|
ghHandleTable,
|
|
hPhoneApp,
|
|
TPHONEAPP_KEY
|
|
)))
|
|
{
|
|
if (ptPhoneApp->ptClient != ptClient)
|
|
{
|
|
ptPhoneApp = NULL;
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, hPhoneApp, 1);
|
|
}
|
|
|
|
return ptPhoneApp;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
ValidateButtonInfo(
|
|
LPPHONEBUTTONINFO pButtonInfoApp,
|
|
LPPHONEBUTTONINFO *ppButtonInfoSP,
|
|
DWORD dwAPIVersion,
|
|
DWORD dwSPIVersion
|
|
)
|
|
{
|
|
//
|
|
// This routine checks the fields in a PHONEBUTTONINFO struct,
|
|
// looking for invalid bit flags and making sure that the
|
|
// various size/offset pairs only reference data within the
|
|
// variable-data portion of the structure. Also, if the
|
|
// specified SPI version is greater than the API version and
|
|
// the fixed structure size differs between the two versions,
|
|
// a larger buffer is allocated, the var data is relocated,
|
|
// and the sizeof/offset pairs are patched.
|
|
//
|
|
|
|
char szFunc[] = "ValidateButtonInfo";
|
|
|
|
DWORD dwTotalSize = pButtonInfoApp->dwTotalSize, dwFixedSizeApp,
|
|
dwFixedSizeSP;
|
|
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwFixedSizeApp = 36; // 9 * sizeof (DWORD)
|
|
break;
|
|
|
|
case TAPI_VERSION1_4:
|
|
case TAPI_VERSION2_0:
|
|
case TAPI_VERSION2_1:
|
|
case TAPI_VERSION2_2:
|
|
case TAPI_VERSION3_0:
|
|
case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeApp = sizeof (PHONEBUTTONINFO);
|
|
break;
|
|
|
|
default:
|
|
|
|
return PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
switch (dwSPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwFixedSizeSP = 36; // 9 * sizeof (DWORD)
|
|
break;
|
|
|
|
case TAPI_VERSION1_4:
|
|
case TAPI_VERSION2_0:
|
|
case TAPI_VERSION2_1:
|
|
case TAPI_VERSION2_2:
|
|
case TAPI_VERSION3_0:
|
|
case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeSP = sizeof (PHONEBUTTONINFO);
|
|
break;
|
|
|
|
default:
|
|
|
|
return PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
if (dwTotalSize < dwFixedSizeApp)
|
|
{
|
|
LOG((TL_TRACE,
|
|
"%sbad dwTotalSize, x%x (minimum valid size=x%x)",
|
|
szFunc,
|
|
dwTotalSize,
|
|
dwFixedSizeApp
|
|
));
|
|
|
|
return PHONEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
if (ISBADSIZEOFFSET(
|
|
dwTotalSize,
|
|
dwFixedSizeApp,
|
|
pButtonInfoApp->dwButtonTextSize,
|
|
pButtonInfoApp->dwButtonTextOffset,
|
|
0,
|
|
szFunc,
|
|
"ButtonText"
|
|
) ||
|
|
|
|
ISBADSIZEOFFSET(
|
|
dwTotalSize,
|
|
dwFixedSizeApp,
|
|
pButtonInfoApp->dwDevSpecificSize,
|
|
pButtonInfoApp->dwDevSpecificOffset,
|
|
0,
|
|
szFunc,
|
|
"DevSpecific"
|
|
))
|
|
{
|
|
return PHONEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
if (dwAPIVersion < TAPI_VERSION1_4)
|
|
{
|
|
goto ValidateButtonInfo_checkFixedSizes;
|
|
}
|
|
|
|
ValidateButtonInfo_checkFixedSizes:
|
|
|
|
if (dwFixedSizeApp < dwFixedSizeSP)
|
|
{
|
|
DWORD dwFixedSizeDiff = dwFixedSizeSP - dwFixedSizeApp;
|
|
LPPHONEBUTTONINFO pButtonInfoSP;
|
|
|
|
|
|
if (!(pButtonInfoSP = ServerAlloc (dwTotalSize + dwFixedSizeDiff)))
|
|
{
|
|
return PHONEERR_NOMEM;
|
|
}
|
|
|
|
CopyMemory (pButtonInfoSP, pButtonInfoApp, dwFixedSizeApp);
|
|
|
|
pButtonInfoSP->dwTotalSize = dwTotalSize + dwFixedSizeDiff;
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pButtonInfoSP) + dwFixedSizeSP,
|
|
((LPBYTE) pButtonInfoApp) + dwFixedSizeApp,
|
|
dwTotalSize - dwFixedSizeApp
|
|
);
|
|
|
|
pButtonInfoSP->dwButtonTextOffset += dwFixedSizeDiff;
|
|
pButtonInfoSP->dwDevSpecificOffset += dwFixedSizeDiff;
|
|
|
|
*ppButtonInfoSP = pButtonInfoSP;
|
|
}
|
|
else
|
|
{
|
|
*ppButtonInfoSP = pButtonInfoApp;
|
|
}
|
|
|
|
//bjm 03/19 - not used - ValidateButtonInfo_return:
|
|
|
|
return 0; // success
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivePhoneClientAccess(
|
|
PTPHONECLIENT ptPhoneClient
|
|
)
|
|
{
|
|
//
|
|
// Assumes ptXxxClient->hXxx has already been referenced,
|
|
// so we can safely access ptXxxClient
|
|
//
|
|
|
|
LOCKTPHONECLIENT (ptPhoneClient);
|
|
|
|
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
UNLOCKTPHONECLIENT (ptPhoneClient);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
DestroytPhone(
|
|
PTPHONE ptPhone,
|
|
BOOL bUnconditional
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
LOG((TL_ERROR, "DestroytPhone: enter, ptPhone=x%p", ptPhone));
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
ptPhone,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
//
|
|
// If the key is bad another thread is in the process of
|
|
// destroying this widget, so just release the mutex &
|
|
// return. Otherwise, if this is a conditional destroy
|
|
// & there are existing clients (which can happen when
|
|
// one app is closing the last client just as another app
|
|
// is creating one) just release the mutex & return.
|
|
// Otherwise, mark the widget as bad and proceed with
|
|
// the destroy; also, send CLOSE msgs to all the clients
|
|
// (note that we have to do this manually rather than via
|
|
// SendMsgToPhoneClients since 1) we don't want to hold the
|
|
// mutex when sending msgs [deadlock], and 2) we mark the
|
|
// dwKey as invalid)
|
|
//
|
|
|
|
{
|
|
BOOL bExit;
|
|
TPOINTERLIST fastClientList, *pClientList = &fastClientList;
|
|
|
|
|
|
if (ptPhone->dwKey == TPHONE_KEY &&
|
|
(bUnconditional == TRUE || ptPhone->ptPhoneClients == NULL))
|
|
{
|
|
if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0)
|
|
{
|
|
//
|
|
// If here we know there's at least a few entries
|
|
// in the fastClientList (DEF_NUM_PTR_LIST_ENTRIES
|
|
// to be exact), so we'll just work with that list
|
|
// and at least get msgs out to a few clients
|
|
//
|
|
|
|
pClientList = &fastClientList;
|
|
|
|
fastClientList.dwNumUsedEntries =
|
|
DEF_NUM_PTR_LIST_ENTRIES;
|
|
}
|
|
|
|
ptPhone->dwKey = INVAL_KEY;
|
|
bExit = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bExit = TRUE;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
if (bExit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pClientList->dwNumUsedEntries)
|
|
{
|
|
DWORD i;
|
|
PTCLIENT ptClient;
|
|
PTPHONECLIENT ptPhoneClient;
|
|
ASYNCEVENTMSG msg;
|
|
|
|
|
|
ZeroMemory (&msg, sizeof (msg));
|
|
|
|
msg.TotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.Msg = PHONE_CLOSE;
|
|
|
|
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
|
|
{
|
|
ptPhoneClient = (PTPHONECLIENT) pClientList->aEntries[i];
|
|
|
|
try
|
|
{
|
|
msg.InitContext =
|
|
ptPhoneClient->ptPhoneApp->InitContext;
|
|
msg.hDevice = ptPhoneClient->hRemotePhone;
|
|
msg.OpenContext = ptPhoneClient->OpenContext;
|
|
|
|
ptClient = ptPhoneClient->ptClient;
|
|
|
|
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY &&
|
|
!FMsgDisabled(
|
|
ptPhoneClient->ptPhoneApp->dwAPIVersion,
|
|
ptPhoneClient->adwEventSubMasks,
|
|
PHONE_CLOSE,
|
|
0
|
|
))
|
|
{
|
|
WriteEventBuffer (ptClient, &msg);
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pClientList != &fastClientList)
|
|
{
|
|
ServerFree (pClientList);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Destroy all the widget's clients. Note that we want to
|
|
// grab the mutex (and we don't have to dup it, since this
|
|
// thread will be the one to close it) each time we reference
|
|
// the list of clients, since another thread might be
|
|
// destroying a client too.
|
|
//
|
|
|
|
{
|
|
HPHONE hPhone;
|
|
|
|
|
|
hMutex = ptPhone->hMutex;
|
|
|
|
destroy_tPhoneClients:
|
|
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
hPhone = (ptPhone->ptPhoneClients ?
|
|
ptPhone->ptPhoneClients->hPhone : (HPHONE) 0);
|
|
|
|
ReleaseMutex (hMutex);
|
|
|
|
if (hPhone)
|
|
{
|
|
DestroytPhoneClient (hPhone);
|
|
goto destroy_tPhoneClients;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Tell the provider to close the widget
|
|
//
|
|
|
|
{
|
|
PTPROVIDER ptProvider = ptPhone->ptProvider;
|
|
PTPHONELOOKUPENTRY pEntry;
|
|
|
|
pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID);
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
WaitForSingleObject (ptProvider->hMutex, INFINITE);
|
|
}
|
|
|
|
if (ptProvider->apfn[SP_PHONECLOSE] &&
|
|
pEntry &&
|
|
!pEntry->bRemoved
|
|
)
|
|
{
|
|
CallSP1(
|
|
ptProvider->apfn[SP_PHONECLOSE],
|
|
"phoneClose",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) ptPhone->hdPhone
|
|
);
|
|
}
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
ReleaseMutex (ptProvider->hMutex);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// NULLify the ptPhone field in the lookup entry, so POpen will
|
|
// know it has to open the SP's phone on the next open request
|
|
//
|
|
|
|
{
|
|
PTPHONELOOKUPENTRY pEntry;
|
|
|
|
|
|
pEntry = GetPhoneLookupEntry (ptPhone->dwDeviceID);
|
|
if (NULL != pEntry)
|
|
{
|
|
pEntry->ptPhone = NULL;
|
|
}
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, ptPhone->hPhone, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DestroytPhoneClient(
|
|
HPHONE hPhone
|
|
)
|
|
{
|
|
BOOL bExit = TRUE, bUnlock = FALSE;
|
|
HANDLE hMutex;
|
|
PTPHONE ptPhone;
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
LOG((TL_TRACE, "DestroytPhoneClient: enter, hPhone=x%x", hPhone));
|
|
|
|
if (!(ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
hPhone,
|
|
TPHONECLIENT_KEY
|
|
)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// If we can get exclusive access to this tPhoneClient then mark
|
|
// it (the dwKey) as bad & continue with teardown. Else, another
|
|
// thread is already in the process of destroying this tPhoneClient
|
|
//
|
|
//
|
|
|
|
if (WaitForExclusivePhoneClientAccess (ptPhoneClient))
|
|
{
|
|
BOOL bSendDevStateMsg = FALSE;
|
|
DWORD dwParam1, dwParam2;
|
|
|
|
|
|
ptPhoneClient->dwKey = INVAL_KEY;
|
|
|
|
UNLOCKTPHONECLIENT (ptPhoneClient);
|
|
|
|
|
|
//
|
|
// Remove tPhoneClient from tPhoneApp's list. Note that we don't
|
|
// have to worry validating the tPhoneApp here, since we know
|
|
// it's valid (another thread trying to destroy the tPhoneApp
|
|
// will be spinning until the tPhoneClient we're destroying here
|
|
// is removed from the tPhoneApp's list)
|
|
//
|
|
|
|
{
|
|
PTPHONEAPP ptPhoneApp = (PTPHONEAPP) ptPhoneClient->ptPhoneApp;
|
|
|
|
|
|
LOCKTPHONEAPP (ptPhoneApp);
|
|
|
|
if (ptPhoneClient->pNextSametPhoneApp)
|
|
{
|
|
ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
|
|
ptPhoneClient->pPrevSametPhoneApp;
|
|
}
|
|
|
|
if (ptPhoneClient->pPrevSametPhoneApp)
|
|
{
|
|
ptPhoneClient->pPrevSametPhoneApp->pNextSametPhoneApp =
|
|
ptPhoneClient->pNextSametPhoneApp;
|
|
}
|
|
else
|
|
{
|
|
ptPhoneApp->ptPhoneClients = ptPhoneClient->pNextSametPhoneApp;
|
|
}
|
|
|
|
UNLOCKTPHONEAPP (ptPhoneApp);
|
|
}
|
|
|
|
|
|
//
|
|
// Remove tPhoneClient from tPhone's list. Note that we don't
|
|
// have to worry about dup-ing the mutex here because we know
|
|
// it's valid & won't get closed before we release it.
|
|
//
|
|
|
|
ptPhone = ptPhoneClient->ptPhone;
|
|
|
|
hMutex = ptPhone->hMutex;
|
|
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
{
|
|
//
|
|
// Also check for ext ver stuff
|
|
//
|
|
|
|
if (ptPhoneClient->dwExtVersion)
|
|
{
|
|
if ((--ptPhone->dwExtVersionCount) == 0 &&
|
|
ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION])
|
|
{
|
|
CallSP2(
|
|
ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) ptPhone->hdPhone,
|
|
(DWORD) 0
|
|
);
|
|
|
|
ptPhone->dwExtVersion = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ptPhoneClient->pNextSametPhone)
|
|
{
|
|
ptPhoneClient->pNextSametPhone->pPrevSametPhone =
|
|
ptPhoneClient->pPrevSametPhone;
|
|
}
|
|
|
|
if (ptPhoneClient->pPrevSametPhone)
|
|
{
|
|
ptPhoneClient->pPrevSametPhone->pNextSametPhone =
|
|
ptPhoneClient->pNextSametPhone;
|
|
}
|
|
else
|
|
{
|
|
ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone;
|
|
}
|
|
|
|
|
|
//
|
|
// Decrement tPhone's NumOwners/Monitors as appropriate
|
|
//
|
|
|
|
if (ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER)
|
|
{
|
|
ptPhone->dwNumOwners--;
|
|
}
|
|
else
|
|
{
|
|
ptPhone->dwNumMonitors--;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
if (ptPhone->ptPhoneClients)
|
|
{
|
|
bSendDevStateMsg = TRUE;
|
|
|
|
dwParam1 =
|
|
(ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
PHONESTATE_OWNER : PHONESTATE_MONITORS);
|
|
|
|
dwParam2 =
|
|
(ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
0 : ptPhone->dwNumMonitors);
|
|
|
|
|
|
//
|
|
// See if we need to reset the status msgs (if so, make
|
|
// sure to check/set the busy flag & not to hold the
|
|
// mutex while calling down to provider - see comments
|
|
// in LSetStatusMessages)
|
|
//
|
|
|
|
if ((ptPhoneClient->dwPhoneStates & ~PHONESTATE_REINIT) ||
|
|
ptPhoneClient->dwButtonModes ||
|
|
ptPhoneClient->dwButtonStates)
|
|
{
|
|
DWORD dwUnionPhoneStates = 0,
|
|
dwUnionButtonModes = 0,
|
|
dwUnionButtonStates = 0;
|
|
PTPHONECLIENT ptPC;
|
|
|
|
|
|
while (ptPhone->dwBusy)
|
|
{
|
|
BOOL bClosed = TRUE;
|
|
|
|
|
|
ReleaseMutex (hMutex);
|
|
Sleep (50);
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
try
|
|
{
|
|
if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
bClosed = FALSE;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
if (bClosed)
|
|
{
|
|
goto releasMutex;
|
|
}
|
|
}
|
|
|
|
for(
|
|
ptPC = ptPhone->ptPhoneClients;
|
|
ptPC;
|
|
ptPC = ptPC->pNextSametPhone
|
|
)
|
|
{
|
|
if (ptPC != ptPhoneClient)
|
|
{
|
|
dwUnionPhoneStates |= ptPC->dwPhoneStates;
|
|
dwUnionButtonModes |= ptPC->dwButtonModes;
|
|
dwUnionButtonStates |= ptPC->dwButtonStates;
|
|
}
|
|
}
|
|
|
|
if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) ||
|
|
(dwUnionButtonModes != ptPhone->dwUnionButtonModes) ||
|
|
(dwUnionButtonStates != ptPhone->dwUnionButtonStates))
|
|
{
|
|
if (ptPhone->ptProvider->apfn
|
|
[SP_PHONESETSTATUSMESSAGES])
|
|
{
|
|
LONG lResult;
|
|
TSPIPROC pfn;
|
|
HDRVPHONE hdPhone = ptPhone->hdPhone;
|
|
|
|
|
|
pfn = ptPhone->ptProvider->
|
|
apfn[SP_PHONESETSTATUSMESSAGES];
|
|
|
|
ptPhone->dwBusy = 1;
|
|
|
|
ReleaseMutex (hMutex);
|
|
|
|
lResult = CallSP4(
|
|
pfn,
|
|
"phoneSetStatusMessages",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) dwUnionPhoneStates,
|
|
(DWORD) dwUnionButtonModes,
|
|
(DWORD) dwUnionButtonStates
|
|
);
|
|
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
try
|
|
{
|
|
if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
ptPhone->dwBusy = 0;
|
|
|
|
if (lResult == 0)
|
|
{
|
|
ptPhone->dwUnionPhoneStates =
|
|
dwUnionPhoneStates;
|
|
ptPhone->dwUnionButtonModes =
|
|
dwUnionButtonModes;
|
|
ptPhone->dwUnionButtonStates =
|
|
dwUnionButtonStates;
|
|
}
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This was the last client so destroy the tPhone too
|
|
//
|
|
|
|
ReleaseMutex (hMutex);
|
|
hMutex = NULL;
|
|
DestroytPhone (ptPhone, FALSE); // conditional destroy
|
|
}
|
|
}
|
|
|
|
releasMutex:
|
|
|
|
if (hMutex)
|
|
{
|
|
ReleaseMutex (hMutex);
|
|
}
|
|
|
|
|
|
//
|
|
// Now that the mutex is released send any necessary msgs
|
|
//
|
|
|
|
if (bSendDevStateMsg)
|
|
{
|
|
SendMsgToPhoneClients(
|
|
ptPhone,
|
|
NULL,
|
|
PHONE_STATE,
|
|
dwParam1,
|
|
dwParam2,
|
|
0
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Decrement reference count by two to remove the initial
|
|
// reference & the reference above
|
|
//
|
|
|
|
DereferenceObject (ghHandleTable, hPhone, 2);
|
|
}
|
|
else
|
|
{
|
|
DereferenceObject (ghHandleTable, hPhone, 1);
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
DestroytPhoneApp(
|
|
HPHONEAPP hPhoneApp
|
|
)
|
|
{
|
|
BOOL bExit = TRUE, bUnlock = FALSE;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
LOG((TL_TRACE, "DestroytPhoneApp: enter, hPhoneApp=x%x", hPhoneApp));
|
|
|
|
|
|
if (!(ptPhoneApp = ReferenceObject (ghHandleTable, hPhoneApp, 0)))
|
|
{
|
|
return (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
|
|
}
|
|
|
|
//
|
|
// Check to make sure that this is a valid tPhoneClient object,
|
|
// then grab the lock and (recheck and) mark object as invalid.
|
|
//
|
|
|
|
LOCKTPHONEAPP (ptPhoneApp);
|
|
|
|
if (ptPhoneApp->dwKey != TPHONEAPP_KEY)
|
|
{
|
|
UNLOCKTPHONEAPP (ptPhoneApp);
|
|
DereferenceObject (ghHandleTable, hPhoneApp, 1);
|
|
return (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
|
|
}
|
|
|
|
ptPhoneApp->dwKey = INVAL_KEY;
|
|
|
|
|
|
//
|
|
// Destroy all the tPhoneClients. Note that we want to grab the
|
|
// lock each time we reference the list of tPhoneClient's, since
|
|
// another thread might be destroying a tPhoneClient too.
|
|
//
|
|
|
|
{
|
|
HPHONE hPhone;
|
|
|
|
|
|
destroy_tPhoneClients:
|
|
|
|
hPhone = (ptPhoneApp->ptPhoneClients ?
|
|
ptPhoneApp->ptPhoneClients->hPhone : (HPHONE) 0);
|
|
|
|
UNLOCKTPHONEAPP (ptPhoneApp);
|
|
|
|
if (hPhone)
|
|
{
|
|
DestroytPhoneClient (hPhone);
|
|
LOCKTPHONEAPP (ptPhoneApp);
|
|
goto destroy_tPhoneClients;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Remove ptPhoneApp from tClient's list. Note that we don't
|
|
// have to worry about dup-ing the mutex here because we know
|
|
// it's valid & won't get closed before we release it.
|
|
//
|
|
|
|
{
|
|
PTCLIENT ptClient = (PTCLIENT) ptPhoneApp->ptClient;
|
|
|
|
|
|
LOCKTCLIENT (ptClient);
|
|
|
|
if (ptPhoneApp->pNext)
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
|
|
}
|
|
|
|
if (ptPhoneApp->pPrev)
|
|
{
|
|
ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
|
|
}
|
|
else
|
|
{
|
|
ptClient->ptPhoneApps = ptPhoneApp->pNext;
|
|
}
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
|
|
|
|
//
|
|
// Decrement total num inits & see if we need to go thru shutdown
|
|
//
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
//assert(TapiGlobals.dwNumLineInits != 0);
|
|
|
|
TapiGlobals.dwNumPhoneInits--;
|
|
|
|
if ((TapiGlobals.dwNumLineInits == 0) &&
|
|
(TapiGlobals.dwNumPhoneInits == 0) &&
|
|
!(TapiGlobals.dwFlags & TAPIGLOBALS_SERVER))
|
|
{
|
|
ServerShutdown();
|
|
gbServerInited = FALSE;
|
|
}
|
|
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
|
|
//
|
|
// Decrement reference count by two to remove the initial
|
|
// reference & the reference above
|
|
//
|
|
|
|
DereferenceObject (ghHandleTable, hPhoneApp, 2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
PhoneProlog(
|
|
PTCLIENT ptClient,
|
|
DWORD dwArgType,
|
|
DWORD dwArg,
|
|
LPVOID phdXxx,
|
|
LPDWORD pdwPrivilege,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTSPIFuncIndex,
|
|
TSPIPROC *ppfnTSPI_phoneXxx,
|
|
PASYNCREQUESTINFO *ppAsyncRequestInfo,
|
|
DWORD dwRemoteRequestID
|
|
#if DBG
|
|
,char *pszFuncName
|
|
#endif
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
DWORD initContext;
|
|
DWORD openContext;
|
|
ULONG_PTR htXxx;
|
|
PTPROVIDER ptProvider;
|
|
|
|
#if DBG
|
|
LOG((TL_TRACE, "PhoneProlog: (phone%s) enter", pszFuncName));
|
|
#else
|
|
LOG((TL_TRACE, "PhoneProlog: -- enter"));
|
|
#endif
|
|
|
|
*phMutex = NULL;
|
|
*pbDupedMutex = FALSE;
|
|
|
|
if (ppAsyncRequestInfo)
|
|
{
|
|
*ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL;
|
|
}
|
|
|
|
if (TapiGlobals.dwNumPhoneInits == 0)
|
|
{
|
|
lResult = PHONEERR_UNINITIALIZED;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
if (ptClient->phContext == (HANDLE) -1)
|
|
{
|
|
lResult = PHONEERR_REINIT;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
switch (dwArgType)
|
|
{
|
|
case ANY_RT_HPHONE:
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
if ((ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
dwArg,
|
|
TPHONECLIENT_KEY
|
|
)))
|
|
{
|
|
if (ptPhoneClient->ptClient != ptClient)
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
else if (ptPhoneClient->dwPrivilege < *pdwPrivilege)
|
|
{
|
|
lResult = PHONEERR_NOTOWNER;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
ptProvider = ptPhoneClient->ptPhone->ptProvider;
|
|
*((HDRVPHONE *) phdXxx) = ptPhoneClient->ptPhone->hdPhone;
|
|
|
|
if (ppAsyncRequestInfo)
|
|
{
|
|
initContext = ptPhoneClient->ptPhoneApp->InitContext;
|
|
openContext = ptPhoneClient->OpenContext;
|
|
htXxx = (ULONG_PTR)ptPhoneClient->ptPhone;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
if (lResult || ptPhoneClient->dwKey != TPHONECLIENT_KEY)
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
else if (ptProvider->dwTSPIOptions &
|
|
LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
if (!WaitForMutex(
|
|
ptProvider->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
ptProvider,
|
|
TPROVIDER_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, dwArg, 1);
|
|
}
|
|
else
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case DEVICE_ID:
|
|
{
|
|
PTPHONELOOKUPENTRY pPhoneLookupEntry;
|
|
|
|
|
|
#if TELE_SERVER
|
|
|
|
//
|
|
// Ff it's a server, map the device id
|
|
//
|
|
|
|
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
|
|
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
|
|
{
|
|
try
|
|
{
|
|
if (*pdwPrivilege >= ptClient->dwPhoneDevices)
|
|
{
|
|
lResult = PHONEERR_BADDEVICEID;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
*pdwPrivilege = (ptClient->pPhoneDevices)[*pdwPrivilege];
|
|
}
|
|
myexcept
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (dwArg && !IsValidPhoneApp ((HPHONEAPP) dwArg, ptClient))
|
|
{
|
|
lResult = PHONEERR_INVALAPPHANDLE;
|
|
}
|
|
else if (!(pPhoneLookupEntry = GetPhoneLookupEntry (*pdwPrivilege)))
|
|
{
|
|
lResult = PHONEERR_BADDEVICEID;
|
|
}
|
|
else if (pPhoneLookupEntry->bRemoved)
|
|
{
|
|
lResult = PHONEERR_NODEVICE;
|
|
}
|
|
else if (!(ptProvider = pPhoneLookupEntry->ptProvider))
|
|
{
|
|
lResult = PHONEERR_NODRIVER;
|
|
}
|
|
else if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
if (!WaitForMutex(
|
|
ptProvider->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
ptProvider,
|
|
TPROVIDER_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
if (lResult)
|
|
{
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure that if caller wants a pointer to a TSPI proc that the
|
|
// func is exported by the provider
|
|
//
|
|
|
|
if (ppfnTSPI_phoneXxx &&
|
|
!(*ppfnTSPI_phoneXxx = ptProvider->apfn[dwTSPIFuncIndex]))
|
|
{
|
|
lResult = PHONEERR_OPERATIONUNAVAIL;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
|
|
//
|
|
// See if we need to alloc & init an ASYNCREQUESTINFO struct
|
|
//
|
|
|
|
if (ppAsyncRequestInfo)
|
|
{
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
|
|
|
|
if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO))))
|
|
{
|
|
lResult = PHONEERR_NOMEM;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
pAsyncRequestInfo->dwLocalRequestID = (DWORD)
|
|
NewObject (ghHandleTable, pAsyncRequestInfo, NULL);
|
|
|
|
if (pAsyncRequestInfo->dwLocalRequestID == 0)
|
|
{
|
|
ServerFree (pAsyncRequestInfo);
|
|
lResult = LINEERR_NOMEM;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
pAsyncRequestInfo->dwKey = TASYNC_KEY;
|
|
pAsyncRequestInfo->ptClient = ptClient;
|
|
pAsyncRequestInfo->InitContext = initContext;
|
|
pAsyncRequestInfo->OpenContext = openContext;
|
|
pAsyncRequestInfo->htXxx = htXxx;
|
|
pAsyncRequestInfo->dwLineFlags = 0;
|
|
|
|
if (dwRemoteRequestID)
|
|
{
|
|
lResult = pAsyncRequestInfo->dwRemoteRequestID = dwRemoteRequestID;
|
|
}
|
|
else
|
|
{
|
|
lResult = pAsyncRequestInfo->dwRemoteRequestID =
|
|
pAsyncRequestInfo->dwLocalRequestID;
|
|
}
|
|
|
|
*ppAsyncRequestInfo = pAsyncRequestInfo;
|
|
}
|
|
|
|
PhoneProlog_return:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"PhoneProlog: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (lResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"PhoneProlog: exit, result=x%x",
|
|
lResult
|
|
));
|
|
#endif
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
void
|
|
PASCAL
|
|
PhoneEpilogSync(
|
|
LONG *plResult,
|
|
HANDLE hMutex,
|
|
BOOL bCloseMutex
|
|
#if DBG
|
|
,char *pszFuncName
|
|
#endif
|
|
)
|
|
{
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"PhoneEpilogSync: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (*plResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"PhoneEpilogSync: -- exit, result=x%x",
|
|
*plResult
|
|
));
|
|
#endif
|
|
}
|
|
|
|
|
|
void
|
|
PASCAL
|
|
PhoneEpilogAsync(
|
|
LONG *plResult,
|
|
LONG lRequestID,
|
|
HANDLE hMutex,
|
|
BOOL bCloseMutex,
|
|
PASYNCREQUESTINFO pAsyncRequestInfo
|
|
#if DBG
|
|
,char *pszFuncName
|
|
#endif
|
|
)
|
|
{
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
|
|
if (lRequestID > 0)
|
|
{
|
|
if (*plResult <= 0)
|
|
{
|
|
if (*plResult == 0)
|
|
{
|
|
LOG((TL_ERROR, "Error: SP returned 0, not request ID"));
|
|
}
|
|
|
|
//
|
|
// If here the service provider returned an error (or 0,
|
|
// which it never should for async requests), so call
|
|
// CompletionProcSP like the service provider normally
|
|
// would, & the worker thread will take care of sending
|
|
// the client a REPLY msg with the request result (we'll
|
|
// return an async request id)
|
|
//
|
|
|
|
CompletionProcSP(
|
|
pAsyncRequestInfo->dwLocalRequestID,
|
|
*plResult
|
|
);
|
|
}
|
|
}
|
|
else if (pAsyncRequestInfo != NULL)
|
|
{
|
|
//
|
|
// If here an error occured before we even called the service
|
|
// provider, so just free the async request (the error will
|
|
// be returned to the client synchronously)
|
|
//
|
|
|
|
DereferenceObject(
|
|
ghHandleTable,
|
|
pAsyncRequestInfo->dwLocalRequestID,
|
|
1
|
|
);
|
|
}
|
|
|
|
*plResult = lRequestID;
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"PhoneEpilogSync: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (lRequestID, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"PhoneEpilogSync: -- exit, result=x%x",
|
|
lRequestID
|
|
));
|
|
#endif
|
|
}
|
|
|
|
|
|
BOOL
|
|
PASCAL
|
|
WaitForExclusivetPhoneAccess(
|
|
PTPHONE ptPhone,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
)
|
|
{
|
|
try
|
|
{
|
|
if (ptPhone->dwKey == TPHONE_KEY &&
|
|
|
|
WaitForMutex(
|
|
ptPhone->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
(LPVOID) ptPhone,
|
|
TPHONE_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
MyReleaseMutex (*phMutex, *pbDupedMutex);
|
|
}
|
|
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
PTPHONEAPP
|
|
PASCAL
|
|
WaitForExclusivePhoneAppAccess(
|
|
HPHONEAPP hPhoneApp,
|
|
PTCLIENT ptClient
|
|
)
|
|
{
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
if (!(ptPhoneApp = ReferenceObject(
|
|
ghHandleTable,
|
|
hPhoneApp,
|
|
TPHONEAPP_KEY
|
|
)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
LOCKTPHONEAPP (ptPhoneApp);
|
|
|
|
if ((ptPhoneApp->dwKey != TPHONEAPP_KEY) ||
|
|
(ptPhoneApp->ptClient != ptClient))
|
|
{
|
|
UNLOCKTPHONEAPP (ptPhoneApp);
|
|
|
|
ptPhoneApp = NULL;
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, hPhoneApp, 1);
|
|
|
|
return ptPhoneApp;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneAppListFromClient(
|
|
PTCLIENT ptClient,
|
|
PTPOINTERLIST *ppList
|
|
)
|
|
{
|
|
if (WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
|
|
dwNumUsedEntries = 0;
|
|
PTPHONEAPP ptPhoneApp = ptClient->ptPhoneApps;
|
|
PTPOINTERLIST pList = *ppList;
|
|
|
|
|
|
while (ptPhoneApp)
|
|
{
|
|
if (dwNumUsedEntries == dwNumTotalEntries)
|
|
{
|
|
//
|
|
// We need a larger list, so alloc a new one, copy the
|
|
// contents of the current one, and the free the current
|
|
// one iff we previously alloc'd it
|
|
//
|
|
|
|
PTPOINTERLIST pNewList;
|
|
|
|
|
|
dwNumTotalEntries <<= 1;
|
|
|
|
if (!(pNewList = ServerAlloc(
|
|
sizeof (TPOINTERLIST) + sizeof (LPVOID) *
|
|
(dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES)
|
|
)))
|
|
{
|
|
UNLOCKTCLIENT (ptClient);
|
|
return PHONEERR_NOMEM;
|
|
}
|
|
|
|
CopyMemory(
|
|
pNewList->aEntries,
|
|
pList->aEntries,
|
|
dwNumUsedEntries * sizeof (LPVOID)
|
|
);
|
|
|
|
if (pList != *ppList)
|
|
{
|
|
ServerFree (pList);
|
|
}
|
|
|
|
pList = pNewList;
|
|
}
|
|
|
|
pList->aEntries[dwNumUsedEntries++] = ptPhoneApp;
|
|
|
|
ptPhoneApp = ptPhoneApp->pNext;
|
|
}
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
|
|
pList->dwNumUsedEntries = dwNumUsedEntries;
|
|
|
|
*ppList = pList;
|
|
}
|
|
else
|
|
{
|
|
return PHONEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneClientListFromPhone(
|
|
PTPHONE ptPhone,
|
|
PTPOINTERLIST *ppList
|
|
)
|
|
{
|
|
BOOL bDupedMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
ptPhone,
|
|
&hMutex,
|
|
&bDupedMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
DWORD dwNumTotalEntries = DEF_NUM_PTR_LIST_ENTRIES,
|
|
dwNumUsedEntries = 0;
|
|
PTPOINTERLIST pList = *ppList;
|
|
PTPHONECLIENT ptPhoneClient = ptPhone->ptPhoneClients;
|
|
|
|
|
|
while (ptPhoneClient)
|
|
{
|
|
if (dwNumUsedEntries == dwNumTotalEntries)
|
|
{
|
|
//
|
|
// We need a larger list, so alloc a new one, copy the
|
|
// contents of the current one, and the free the current
|
|
// one iff we previously alloc'd it
|
|
//
|
|
|
|
PTPOINTERLIST pNewList;
|
|
|
|
|
|
dwNumTotalEntries <<= 1;
|
|
|
|
if (!(pNewList = ServerAlloc(
|
|
sizeof (TPOINTERLIST) + sizeof (LPVOID) *
|
|
(dwNumTotalEntries - DEF_NUM_PTR_LIST_ENTRIES)
|
|
)))
|
|
{
|
|
MyReleaseMutex (hMutex, bDupedMutex);
|
|
return PHONEERR_NOMEM;
|
|
}
|
|
|
|
CopyMemory(
|
|
pNewList->aEntries,
|
|
pList->aEntries,
|
|
dwNumUsedEntries * sizeof (LPVOID)
|
|
);
|
|
|
|
if (pList != *ppList)
|
|
{
|
|
ServerFree (pList);
|
|
}
|
|
|
|
pList = pNewList;
|
|
}
|
|
|
|
pList->aEntries[dwNumUsedEntries++] = ptPhoneClient;
|
|
|
|
ptPhoneClient = ptPhoneClient->pNextSametPhone;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bDupedMutex);
|
|
|
|
pList->dwNumUsedEntries = dwNumUsedEntries;
|
|
|
|
*ppList = pList;
|
|
}
|
|
else
|
|
{
|
|
return PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
PASCAL
|
|
SendMsgToPhoneClients(
|
|
PTPHONE ptPhone,
|
|
PTPHONECLIENT ptPhoneClientToExclude,
|
|
DWORD Msg,
|
|
DWORD Param1,
|
|
DWORD Param2,
|
|
DWORD Param3
|
|
)
|
|
{
|
|
DWORD i;
|
|
TPOINTERLIST clientList, *pClientList = &clientList;
|
|
ASYNCEVENTMSG msg;
|
|
|
|
|
|
if (Msg == PHONE_STATE && Param1 & PHONESTATE_REINIT)
|
|
{
|
|
SendReinitMsgToAllXxxApps();
|
|
|
|
if (Param1 == PHONESTATE_REINIT)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Param1 &= ~PHONESTATE_REINIT;
|
|
}
|
|
}
|
|
|
|
if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
msg.TotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.fnPostProcessProcHandle = 0;
|
|
msg.Msg = Msg;
|
|
msg.Param1 = Param1;
|
|
msg.Param2 = Param2;
|
|
msg.Param3 = Param3;
|
|
|
|
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
|
|
{
|
|
try
|
|
{
|
|
PTCLIENT ptClient;
|
|
PTPHONECLIENT ptPhoneClient = pClientList->aEntries[i];
|
|
|
|
|
|
if (ptPhoneClient == ptPhoneClientToExclude)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (FMsgDisabled (
|
|
ptPhoneClient->ptPhoneApp->dwAPIVersion,
|
|
ptPhoneClient->adwEventSubMasks,
|
|
(DWORD) Msg,
|
|
(DWORD) Param1
|
|
))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (Msg == PHONE_STATE)
|
|
{
|
|
DWORD phoneStates = Param1;
|
|
|
|
|
|
//
|
|
// Munge the state flags so we don't pass
|
|
// unexpected flags to old apps
|
|
//
|
|
|
|
switch (ptPhoneClient->dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
phoneStates &= AllPhoneStates1_0;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION1_4:
|
|
// case TAPI_VERSION_CURRENT:
|
|
|
|
phoneStates &= AllPhoneStates1_4;
|
|
break;
|
|
}
|
|
|
|
if (Param1 & PHONESTATE_CAPSCHANGE)
|
|
{
|
|
}
|
|
|
|
if (ptPhoneClient->dwPhoneStates & (DWORD) phoneStates)
|
|
{
|
|
msg.Param1 = phoneStates;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (Msg == PHONE_BUTTON)
|
|
{
|
|
DWORD buttonModes = Param2,
|
|
buttonStates = Param3;
|
|
|
|
|
|
//
|
|
// Munge the state flags so we don't pass
|
|
// unexpected flags to old apps
|
|
//
|
|
|
|
switch (ptPhoneClient->dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
buttonStates &= AllButtonStates1_0;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION1_4:
|
|
// case TAPI_VERSION_CURRENT:
|
|
|
|
buttonStates &= AllButtonStates1_4;
|
|
break;
|
|
}
|
|
|
|
if (((DWORD) buttonModes & ptPhoneClient->dwButtonModes) &&
|
|
((DWORD) buttonStates & ptPhoneClient->dwButtonStates))
|
|
{
|
|
msg.Param2 = buttonModes;
|
|
msg.Param3 = buttonStates;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
msg.InitContext =
|
|
((PTPHONEAPP) ptPhoneClient->ptPhoneApp)->InitContext;
|
|
msg.hDevice = ptPhoneClient->hRemotePhone;
|
|
msg.OpenContext = ptPhoneClient->OpenContext;
|
|
|
|
ptClient = ptPhoneClient->ptClient;
|
|
|
|
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY)
|
|
{
|
|
WriteEventBuffer (ptClient, &msg);
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
// just continue
|
|
}
|
|
}
|
|
|
|
if (pClientList != &clientList)
|
|
{
|
|
ServerFree (pClientList);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PASCAL
|
|
PhoneEventProc(
|
|
HTAPIPHONE htPhone,
|
|
DWORD dwMsg,
|
|
ULONG_PTR Param1,
|
|
ULONG_PTR Param2,
|
|
ULONG_PTR Param3
|
|
)
|
|
{
|
|
PTPHONE ptPhone = (PTPHONE)htPhone;
|
|
|
|
switch (dwMsg)
|
|
{
|
|
case PHONE_CLOSE:
|
|
{
|
|
if (NULL == ptPhone)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ptPhone->dwKey == TINCOMPLETEPHONE_KEY)
|
|
{
|
|
//
|
|
// The device is in the process of getting opened but
|
|
// the key has not been set & the Open() func still owns
|
|
// the mutex and has stuff to do, so repost the msg
|
|
// and try again later. (Set Param3 to special value
|
|
// to indicate this repost, so EventProcSP doesn't recurse)
|
|
//
|
|
|
|
PhoneEventProcSP (htPhone, PHONE_CLOSE, 0, 0, 0xdeadbeef);
|
|
}
|
|
else if (ptPhone->dwKey == TPHONE_KEY)
|
|
{
|
|
DestroytPhone (ptPhone, TRUE); // unconditional destroy
|
|
}
|
|
|
|
break;
|
|
}
|
|
case PHONE_DEVSPECIFIC:
|
|
case PHONE_STATE:
|
|
case PHONE_BUTTON:
|
|
{
|
|
if (dwMsg == PHONE_STATE &&
|
|
ptPhone == NULL &&
|
|
Param1 & PHONESTATE_REINIT)
|
|
{
|
|
SendReinitMsgToAllXxxApps();
|
|
}
|
|
else
|
|
{
|
|
SendMsgToPhoneClients(
|
|
ptPhone,
|
|
NULL,
|
|
dwMsg,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
DWORD_CAST(Param2,__FILE__,__LINE__),
|
|
DWORD_CAST(Param3,__FILE__,__LINE__)
|
|
);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case PHONE_CREATE:
|
|
{
|
|
LONG lResult;
|
|
DWORD dwDeviceID;
|
|
TSPIPROC pfnTSPI_providerCreatePhoneDevice;
|
|
PTPROVIDER ptProvider = (PTPROVIDER) Param1;
|
|
PTPHONELOOKUPTABLE pTable, pPrevTable;
|
|
PTPHONELOOKUPENTRY pEntry;
|
|
PTPROVIDER ptProvider2;
|
|
|
|
|
|
pfnTSPI_providerCreatePhoneDevice =
|
|
ptProvider->apfn[SP_PROVIDERCREATEPHONEDEVICE];
|
|
|
|
assert (pfnTSPI_providerCreatePhoneDevice != NULL);
|
|
|
|
|
|
//
|
|
// Search for a table entry (create a new table if we can't find
|
|
// a free entry in an existing table)
|
|
//
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
// Check to make sure provider is still loaded
|
|
ptProvider2 = TapiGlobals.ptProviders;
|
|
while (ptProvider2 && ptProvider2 != ptProvider)
|
|
{
|
|
ptProvider2 = ptProvider2->pNext;
|
|
}
|
|
|
|
if (ptProvider2 != ptProvider)
|
|
{
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
return;
|
|
}
|
|
|
|
if (!gbQueueSPEvents)
|
|
{
|
|
//
|
|
// We're shutting down, so bail out
|
|
//
|
|
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
return;
|
|
}
|
|
|
|
pTable = pPrevTable = TapiGlobals.pPhoneLookup;
|
|
|
|
while (pTable &&
|
|
!(pTable->dwNumUsedEntries < pTable->dwNumTotalEntries))
|
|
{
|
|
pPrevTable = pTable;
|
|
|
|
pTable = pTable->pNext;
|
|
}
|
|
|
|
if (!pTable)
|
|
{
|
|
if (!(pTable = ServerAlloc(
|
|
sizeof (TPHONELOOKUPTABLE) +
|
|
(2 * pPrevTable->dwNumTotalEntries - 1) *
|
|
sizeof (TPHONELOOKUPENTRY)
|
|
)))
|
|
{
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
break;
|
|
}
|
|
|
|
pPrevTable->pNext = pTable;
|
|
|
|
pTable->dwNumTotalEntries = 2 * pPrevTable->dwNumTotalEntries;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the table entry
|
|
//
|
|
|
|
pEntry = pTable->aEntries + pTable->dwNumUsedEntries;
|
|
|
|
dwDeviceID = TapiGlobals.dwNumPhones;
|
|
|
|
if ((pEntry->hMutex = MyCreateMutex()))
|
|
{
|
|
pEntry->ptProvider = (PTPROVIDER) Param1;
|
|
|
|
|
|
//
|
|
// Now call the creation & negotiation entrypoints, and if all
|
|
// goes well increment the counts & send msgs to the clients
|
|
//
|
|
|
|
if ((lResult = CallSP2(
|
|
pfnTSPI_providerCreatePhoneDevice,
|
|
"providerCreatePhoneDevice",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) Param2,
|
|
(DWORD) dwDeviceID
|
|
|
|
)) == 0)
|
|
{
|
|
TSPIPROC pfnTSPI_phoneNegotiateTSPIVersion =
|
|
ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION];
|
|
TPOINTERLIST clientList, *pClientList = &clientList;
|
|
|
|
|
|
if (pfnTSPI_phoneNegotiateTSPIVersion &&
|
|
(lResult = CallSP4(
|
|
pfnTSPI_phoneNegotiateTSPIVersion,
|
|
"",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) TAPI_VERSION1_0,
|
|
(DWORD) TAPI_VERSION_CURRENT,
|
|
(ULONG_PTR) &pEntry->dwSPIVersion
|
|
|
|
)) == 0)
|
|
{
|
|
PTCLIENT ptClient;
|
|
ASYNCEVENTMSG msg;
|
|
|
|
|
|
GetPermPhoneIDAndInsertInTable(
|
|
ptProvider,
|
|
dwDeviceID,
|
|
pEntry->dwSPIVersion
|
|
);
|
|
|
|
pTable->dwNumUsedEntries++;
|
|
|
|
TapiGlobals.dwNumPhones++;
|
|
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
AppendNewDeviceInfo (FALSE, dwDeviceID);
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
msg.TotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.fnPostProcessProcHandle = 0;
|
|
msg.hDevice = 0;
|
|
msg.OpenContext = 0;
|
|
msg.Param2 = 0;
|
|
msg.Param3 = 0;
|
|
|
|
// only send the message if the client is an
|
|
// admin or we're not a telephony server
|
|
// we don't want to send the message to non-admin
|
|
// clients, because their phones have not changed.
|
|
if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
|
|
{
|
|
lResult = GetClientList (TRUE, &pClientList);
|
|
}
|
|
else
|
|
{
|
|
lResult = GetClientList (FALSE, &pClientList);
|
|
}
|
|
if (lResult == S_OK)
|
|
{
|
|
DWORD i;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
for (i = 0; i < pClientList->dwNumUsedEntries; ++i)
|
|
{
|
|
ptClient = (PTCLIENT) pClientList->aEntries[i];
|
|
if (!WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
continue;
|
|
}
|
|
ptPhoneApp = ptClient->ptPhoneApps;
|
|
|
|
while (ptPhoneApp)
|
|
{
|
|
if (ptPhoneApp->dwAPIVersion == TAPI_VERSION1_0)
|
|
{
|
|
msg.Msg = PHONE_STATE;
|
|
msg.Param1 = PHONESTATE_REINIT;
|
|
}
|
|
else
|
|
{
|
|
msg.Msg = PHONE_CREATE;
|
|
msg.Param1 = dwDeviceID;
|
|
}
|
|
|
|
if (!FMsgDisabled(
|
|
ptPhoneApp->dwAPIVersion,
|
|
ptPhoneApp->adwEventSubMasks,
|
|
(DWORD) msg.Msg,
|
|
(DWORD) msg.Param1
|
|
))
|
|
{
|
|
msg.InitContext = ptPhoneApp->InitContext;
|
|
|
|
WriteEventBuffer (ptClient, &msg);
|
|
}
|
|
|
|
ptPhoneApp = ptPhoneApp->pNext;
|
|
}
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pClientList != &clientList)
|
|
{
|
|
ServerFree (pClientList);
|
|
}
|
|
}
|
|
|
|
if (lResult)
|
|
{
|
|
MyCloseMutex (pEntry->hMutex);
|
|
}
|
|
}
|
|
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
break;
|
|
}
|
|
case PHONE_REMOVE:
|
|
{
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
HANDLE hLookupEntryMutex = NULL;
|
|
BOOL bOK = FALSE;
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
if (!(pLookupEntry = GetPhoneLookupEntry ((DWORD) Param1)) ||
|
|
pLookupEntry->bRemoved)
|
|
{
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
return;
|
|
}
|
|
|
|
if ( pLookupEntry->hMutex )
|
|
{
|
|
bOK = DuplicateHandle(
|
|
TapiGlobals.hProcess,
|
|
pLookupEntry->hMutex,
|
|
TapiGlobals.hProcess,
|
|
&hLookupEntryMutex,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
}
|
|
|
|
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
|
|
|
|
if ( !bOK )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Wait for the LookupEntry's mutex on the duplicate handle
|
|
//
|
|
if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Mark the lookup table entry as removed
|
|
//
|
|
|
|
pLookupEntry->bRemoved = 1;
|
|
|
|
//
|
|
// Release the mutex and close the duplicate handle
|
|
//
|
|
ReleaseMutex (hLookupEntryMutex);
|
|
CloseHandle (hLookupEntryMutex);
|
|
hLookupEntryMutex = NULL;
|
|
|
|
if (pLookupEntry->ptPhone)
|
|
{
|
|
DestroytPhone (pLookupEntry->ptPhone, TRUE); // unconditional destroy
|
|
}
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
//
|
|
// Close the mutex to reduce overall handle count
|
|
//
|
|
|
|
MyCloseMutex (pLookupEntry->hMutex);
|
|
pLookupEntry->hMutex = NULL;
|
|
|
|
RemoveDeviceInfoEntry (FALSE, DWORD_CAST(Param1,__FILE__,__LINE__));
|
|
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
|
|
|
|
SendAMsgToAllPhoneApps(
|
|
TAPI_VERSION2_0 | 0x80000000,
|
|
PHONE_REMOVE,
|
|
DWORD_CAST(Param1,__FILE__,__LINE__),
|
|
0,
|
|
0
|
|
);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
LOG((TL_ERROR, "PhoneEventProc: unknown msg, dwMsg=%ld", dwMsg));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CALLBACK
|
|
PhoneEventProcSP(
|
|
HTAPIPHONE htPhone,
|
|
DWORD dwMsg,
|
|
ULONG_PTR Param1,
|
|
ULONG_PTR Param2,
|
|
ULONG_PTR Param3
|
|
)
|
|
{
|
|
PSPEVENT pSPEvent;
|
|
|
|
LOG((TL_TRACE,
|
|
"PhoneEventProc: enter\n\thtPhone=x%lx, Msg=x%lx\n" \
|
|
"\tP1=x%lx, P2=x%lx, P3=x%lx",
|
|
htPhone,
|
|
dwMsg,
|
|
Param1,
|
|
Param2,
|
|
Param3
|
|
));
|
|
|
|
if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT))))
|
|
{
|
|
pSPEvent->dwType = SP_PHONE_EVENT;
|
|
pSPEvent->htPhone = htPhone;
|
|
pSPEvent->dwMsg = dwMsg;
|
|
pSPEvent->dwParam1 = Param1;
|
|
pSPEvent->dwParam2 = Param2;
|
|
pSPEvent->dwParam3 = Param3;
|
|
|
|
if (!QueueSPEvent (pSPEvent))
|
|
{
|
|
ServerFree (pSPEvent);
|
|
}
|
|
}
|
|
else if (dwMsg != PHONE_CLOSE || Param3 != 0xdeadbeef)
|
|
{
|
|
//
|
|
// Alloc failed, so call the event proc within the SP's context
|
|
// (but not if it's CLOSE msg and Param3 == 0xdeadbeef,
|
|
// which means the real EventProc() is calling us directly &
|
|
// we don't want to recurse)
|
|
//
|
|
|
|
PhoneEventProc (htPhone, dwMsg, Param1, Param2, Param3);
|
|
}
|
|
}
|
|
|
|
void
|
|
WINAPI
|
|
PClose(
|
|
PTCLIENT ptClient,
|
|
PPHONECLOSE_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
0, // provider func index
|
|
NULL, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"Close" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
if ((ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
TPHONECLIENT_KEY
|
|
)))
|
|
{
|
|
pParams->dwCallbackInstance = ptPhoneClient->OpenContext;
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
}
|
|
DestroytPhoneClient ((HPHONE) pParams->hPhone);
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"Close"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
PDevSpecific_PostProcess(
|
|
PASYNCREQUESTINFO pAsyncRequestInfo,
|
|
PASYNCEVENTMSG pAsyncEventMsg,
|
|
LPVOID *ppBuf
|
|
)
|
|
{
|
|
PASYNCEVENTMSG pNewAsyncEventMsg = (PASYNCEVENTMSG)
|
|
pAsyncRequestInfo->dwParam3;
|
|
|
|
|
|
CopyMemory (pNewAsyncEventMsg, pAsyncEventMsg, sizeof (ASYNCEVENTMSG));
|
|
|
|
*ppBuf = pNewAsyncEventMsg;
|
|
|
|
if (pAsyncEventMsg->Param2 == 0) // success
|
|
{
|
|
//
|
|
// Make sure to keep the total size 64-bit aligned
|
|
//
|
|
|
|
pNewAsyncEventMsg->TotalSize +=
|
|
(DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__) + 7) & 0xfffffff8;
|
|
|
|
|
|
pNewAsyncEventMsg->Param3 = DWORD_CAST(pAsyncRequestInfo->dwParam1,__FILE__,__LINE__); // lpParams
|
|
pNewAsyncEventMsg->Param4 = DWORD_CAST(pAsyncRequestInfo->dwParam2,__FILE__,__LINE__); // dwSize
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PDevSpecific(
|
|
PTCLIENT ptClient,
|
|
PPHONEDEVSPECIFIC_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneDevSpecific;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (ISBADSIZEOFFSET(
|
|
dwParamsBufferSize,
|
|
0,
|
|
pParams->dwParamsSize,
|
|
pParams->dwParamsOffset,
|
|
sizeof(DWORD),
|
|
"PDevSpecific",
|
|
"pParams->Params"
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEDEVSPECIFIC, // provider func index
|
|
&pfnTSPI_phoneDevSpecific, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"DevSpecific" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
LPBYTE pBuf;
|
|
|
|
|
|
//
|
|
// Alloc a shadow buf that the SP can use until it completes this
|
|
// request. Make sure there's enough extra space in the buf for
|
|
// an ASYNCEVENTMSG header so we don't have to alloc yet another
|
|
// buf in the post processing proc when preparing the completion
|
|
// msg to send to the client, and that the msg is 64-bit aligned.
|
|
//
|
|
|
|
if (!(pBuf = ServerAlloc(
|
|
((pParams->dwParamsSize + 7) & 0xfffffff8) +
|
|
sizeof (ASYNCEVENTMSG)
|
|
)))
|
|
{
|
|
lRequestID = PHONEERR_NOMEM;
|
|
goto PDevSpecific_epilog;
|
|
}
|
|
|
|
CopyMemory(
|
|
pBuf + sizeof (ASYNCEVENTMSG),
|
|
pDataBuf + pParams->dwParamsOffset,
|
|
pParams->dwParamsSize
|
|
);
|
|
|
|
pAsyncRequestInfo->pfnPostProcess = PDevSpecific_PostProcess;
|
|
pAsyncRequestInfo->dwParam1 = pParams->hpParams;
|
|
pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
|
|
pAsyncRequestInfo->dwParam3 = (ULONG_PTR) pBuf;
|
|
|
|
pAsyncRequestInfo->hfnClientPostProcessProc =
|
|
pParams->hfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneDevSpecific,
|
|
"phoneDevSpecific",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) (pParams->dwParamsSize ?
|
|
pBuf + sizeof (ASYNCEVENTMSG) : NULL),
|
|
(DWORD) pParams->dwParamsSize
|
|
);
|
|
}
|
|
|
|
PDevSpecific_epilog:
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"DevSpecific"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetButtonInfo(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETBUTTONINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetButtonInfo;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwButtonInfoTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETBUTTONINFO, // provider func index
|
|
&pfnTSPI_phoneGetButtonInfo,// provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetButtonInfo" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
|
|
dwFixedSizeClient, dwFixedSizeSP;
|
|
LPPHONEBUTTONINFO pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf,
|
|
pButtonInfo2 = (LPPHONEBUTTONINFO) NULL;
|
|
|
|
|
|
//
|
|
// Safely retrieve the API & SPI versions
|
|
//
|
|
|
|
if (GetPhoneVersions(
|
|
pParams->hPhone,
|
|
&dwAPIVersion,
|
|
&dwSPIVersion
|
|
|
|
) != 0)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PGetButtonInfo_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure for the specified API
|
|
// version, verify client's buffer is big enough
|
|
//
|
|
|
|
dwTotalSize = pParams->dwButtonInfoTotalSize;
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwFixedSizeClient = 0x24;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeClient = sizeof (PHONEBUTTONINFO);
|
|
break;
|
|
}
|
|
|
|
if (dwTotalSize < dwFixedSizeClient)
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetButtonInfo_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure expected by the SP
|
|
//
|
|
|
|
switch (dwSPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwFixedSizeSP = 0x24;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeSP = sizeof (PHONEBUTTONINFO);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// If the client's buffer is < the fixed size of that expected by
|
|
// the SP (client is lower version than SP) then allocate an
|
|
// intermediate buffer
|
|
//
|
|
|
|
if (dwTotalSize < dwFixedSizeSP)
|
|
{
|
|
if (!(pButtonInfo2 = ServerAlloc (dwFixedSizeSP)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PGetButtonInfo_epilog;
|
|
}
|
|
|
|
pButtonInfo = pButtonInfo2;
|
|
dwTotalSize = dwFixedSizeSP;
|
|
}
|
|
|
|
|
|
InitTapiStruct(
|
|
pButtonInfo,
|
|
dwTotalSize,
|
|
dwFixedSizeSP,
|
|
(pButtonInfo2 == NULL ? TRUE : FALSE)
|
|
);
|
|
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetButtonInfo,
|
|
"phoneGetButtonInfo",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(ULONG_PTR) pButtonInfo
|
|
|
|
)) == 0)
|
|
{
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
//
|
|
// Add the fields we're responsible for
|
|
//
|
|
|
|
|
|
//
|
|
// Munge fields where appropriate for old apps (don't want to
|
|
// pass back flags that they won't understand)
|
|
//
|
|
|
|
|
|
//
|
|
// If an intermediate buffer was used then copy the bits back
|
|
// to the the original buffer, & free the intermediate buffer.
|
|
// Also reset the dwUsedSize field to the fixed size of the
|
|
// structure for the specifed version, since any data in the
|
|
// variable portion is garbage as far as the client is concerned.
|
|
//
|
|
|
|
if (pButtonInfo == pButtonInfo2)
|
|
{
|
|
pButtonInfo = (LPPHONEBUTTONINFO) pDataBuf;
|
|
|
|
CopyMemory (pButtonInfo, pButtonInfo2, dwFixedSizeClient);
|
|
|
|
ServerFree (pButtonInfo2);
|
|
|
|
pButtonInfo->dwTotalSize = pParams->dwButtonInfoTotalSize;
|
|
pButtonInfo->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwButtonInfoOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
|
|
pButtonInfo->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetButtonInfo_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetButtonInfo"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetData(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETDATA_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetData;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETDATA, // provider func index
|
|
&pfnTSPI_phoneGetData, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetData" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if ((pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneGetData,
|
|
"phoneGetData",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwDataID,
|
|
(ULONG_PTR) pDataBuf,
|
|
(DWORD) pParams->dwSize
|
|
|
|
)) == 0)
|
|
{
|
|
//
|
|
// Indicate offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwDataOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pParams->dwSize;
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetData"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetDevCaps(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETDEVCAPS_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneGetDevCaps;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwPhoneCapsTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
DEVICE_ID, // widget type
|
|
(DWORD) pParams->hPhoneApp, // client widget handle
|
|
NULL, // provider widget handle
|
|
&dwDeviceID, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETDEVCAPS, // provider func index
|
|
&pfnTSPI_phoneGetDevCaps, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetDevCaps" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
|
|
dwFixedSizeClient, dwFixedSizeSP;
|
|
LPPHONECAPS pCaps = (LPPHONECAPS) pDataBuf,
|
|
pCaps2 = (LPPHONECAPS) NULL;
|
|
|
|
|
|
//
|
|
// Verify API & SPI version compatibility
|
|
//
|
|
|
|
dwAPIVersion = pParams->dwAPIVersion;
|
|
|
|
dwSPIVersion =
|
|
(GetPhoneLookupEntry (dwDeviceID))->dwSPIVersion;
|
|
|
|
if (!IsAPIVersionInRange (dwAPIVersion, dwSPIVersion))
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PGetDevCaps_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Verify Ext version compatibility
|
|
//
|
|
|
|
if (!IsValidPhoneExtVersion (dwDeviceID, pParams->dwExtVersion))
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
|
|
goto PGetDevCaps_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure for the specified API
|
|
// version, verify client's buffer is big enough
|
|
//
|
|
|
|
dwTotalSize = pParams->dwPhoneCapsTotalSize;
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
case TAPI_VERSION1_4:
|
|
|
|
dwFixedSizeClient = 144; // 36 * sizeof (DWORD)
|
|
break;
|
|
|
|
case TAPI_VERSION2_0:
|
|
case TAPI_VERSION2_1:
|
|
|
|
dwFixedSizeClient = 180; // 45 * sizeof (DWORD)
|
|
break;
|
|
|
|
// case TAPI_VERSION2_2:
|
|
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeClient = sizeof (PHONECAPS);
|
|
break;
|
|
}
|
|
|
|
if (dwTotalSize < dwFixedSizeClient)
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetDevCaps_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure expected by the SP
|
|
//
|
|
|
|
switch (dwSPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
case TAPI_VERSION1_4:
|
|
|
|
dwFixedSizeSP = 144; // 36 * sizeof (DWORD)
|
|
break;
|
|
|
|
case TAPI_VERSION2_0:
|
|
case TAPI_VERSION2_1:
|
|
|
|
dwFixedSizeSP = 180; // 45 * sizeof (DWORD)
|
|
break;
|
|
|
|
// case TAPI_VERSION2_2:
|
|
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeSP = sizeof (PHONECAPS);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// If the client's buffer is < the fixed size of that expected by
|
|
// the SP (client is lower version than SP) then allocate an
|
|
// intermediate buffer
|
|
//
|
|
|
|
if (dwTotalSize < dwFixedSizeSP)
|
|
{
|
|
if (!(pCaps2 = ServerAlloc (dwFixedSizeSP)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PGetDevCaps_epilog;
|
|
}
|
|
|
|
pCaps = pCaps2;
|
|
dwTotalSize = dwFixedSizeSP;
|
|
}
|
|
|
|
|
|
InitTapiStruct(
|
|
pCaps,
|
|
dwTotalSize,
|
|
dwFixedSizeSP,
|
|
(pCaps2 == NULL ? TRUE : FALSE)
|
|
);
|
|
|
|
if ((pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneGetDevCaps,
|
|
"phoneGetDevCaps",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) dwSPIVersion,
|
|
(DWORD) pParams->dwExtVersion,
|
|
(ULONG_PTR) pCaps
|
|
|
|
)) == 0)
|
|
{
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Add the fields we're responsible for
|
|
//
|
|
|
|
pCaps->dwPhoneStates |= PHONESTATE_OWNER |
|
|
PHONESTATE_MONITORS |
|
|
PHONESTATE_REINIT;
|
|
|
|
|
|
//
|
|
// Munge fields where appropriate for old apps (don't want to
|
|
// pass back flags that they won't understand)
|
|
//
|
|
|
|
|
|
//
|
|
// If an intermediate buffer was used then copy the bits back
|
|
// to the the original buffer, & free the intermediate buffer.
|
|
// Also reset the dwUsedSize field to the fixed size of the
|
|
// structure for the specifed version, since any data in the
|
|
// variable portion is garbage as far as the client is concerned.
|
|
//
|
|
|
|
if (pCaps == pCaps2)
|
|
{
|
|
pCaps = (LPPHONECAPS) pDataBuf;
|
|
|
|
CopyMemory (pCaps, pCaps2, dwFixedSizeClient);
|
|
|
|
ServerFree (pCaps2);
|
|
|
|
pCaps->dwTotalSize = pParams->dwPhoneCapsTotalSize;
|
|
pCaps->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwPhoneCapsOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCaps->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetDevCaps_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetDevCaps"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetDisplay(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETDISPLAY_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetDisplay;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwDisplayTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETDISPLAY, // provider func index
|
|
&pfnTSPI_phoneGetDisplay, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetDisplay" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
LPVARSTRING pDisplay = (LPVARSTRING) pDataBuf;
|
|
|
|
|
|
if (!InitTapiStruct(
|
|
pDisplay,
|
|
pParams->dwDisplayTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetDisplay_epilog;
|
|
}
|
|
|
|
if ((pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneGetDisplay,
|
|
"phoneGetDisplay",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) pDisplay
|
|
|
|
)) == 0)
|
|
{
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
//
|
|
// Indicate how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwDisplayOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDisplay->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetDisplay_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetDisplay"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetGain(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETGAIN_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetGain;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETGAIN, // provider func index
|
|
&pfnTSPI_phoneGetGain, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetGain" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
|
|
(pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV;
|
|
}
|
|
else
|
|
{
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetGain,
|
|
"phoneGetGain",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(ULONG_PTR) &pParams->dwGain
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETGAIN_PARAMS);
|
|
}
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetGain"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetHookSwitch(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETHOOKSWITCH_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetHookSwitch;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETHOOKSWITCH, // provider func index
|
|
&pfnTSPI_phoneGetHookSwitch,// provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetHookSwitch" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if ((pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneGetHookSwitch,
|
|
"phoneGetHookSwitch",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) &pParams->dwHookSwitchDevs
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETHOOKSWITCH_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetHookSwitch"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetIcon(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETICON_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
WCHAR *pszDeviceClass;
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneGetIcon;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if ((pParams->dwDeviceClassOffset != TAPI_NO_DATA) &&
|
|
|
|
IsBadStringParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwDeviceClassOffset
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ?
|
|
NULL : pDataBuf + pParams->dwDeviceClassOffset);
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
DEVICE_ID, // widget type
|
|
0, // client widget handle
|
|
NULL, // provider widget handle
|
|
&(pParams->dwDeviceID), // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETICON, // provider func index
|
|
&pfnTSPI_phoneGetIcon, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetIcon" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetIcon,
|
|
"phoneGetIcon",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) pParams->dwDeviceID,
|
|
(ULONG_PTR) pszDeviceClass,
|
|
(ULONG_PTR) &pParams->hIcon
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS);
|
|
}
|
|
}
|
|
else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
|
|
{
|
|
if ((pszDeviceClass == NULL) ||
|
|
(_wcsicmp(pszDeviceClass, L"tapi/phone") == 0))
|
|
{
|
|
pParams->hIcon = TapiGlobals.hPhoneIcon;
|
|
pParams->lResult = 0;
|
|
*pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALDEVICECLASS;
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetIcon"
|
|
);
|
|
}
|
|
|
|
void
|
|
WINAPI
|
|
PGetIDEx(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETID_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
|
|
LPBYTE pDeviceClass = pDataBuf + pParams->dwDeviceClassOffset;
|
|
LPWSTR pDeviceClassCopy = NULL;
|
|
LPWSTR szStringId1 = NULL;
|
|
LPWSTR szStringId2 = NULL;
|
|
LPVARSTRING pID = (LPVARSTRING) pDataBuf;
|
|
DWORD dwAvailSize;
|
|
|
|
//
|
|
// Make a copy of the device class
|
|
//
|
|
pDeviceClassCopy = (LPWSTR) ServerAlloc( (1 + wcslen( (LPWSTR)pDeviceClass )) * sizeof(WCHAR));
|
|
if (!pDeviceClassCopy)
|
|
{
|
|
LOG((TL_ERROR, "PGetIDEx: failed to allocate DeviceClassCopy"));
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
}
|
|
|
|
wcscpy(pDeviceClassCopy, (LPWSTR)pDeviceClass);
|
|
|
|
//
|
|
// First call PGetID
|
|
//
|
|
PGetID( ptClient,
|
|
pParams,
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pdwNumBytesReturned);
|
|
|
|
//
|
|
// if PGetID was successful and the request was for a wave device,
|
|
// translate the device ID into a string ID
|
|
//
|
|
if ( (pParams->lResult == 0) &&
|
|
!(pID->dwNeededSize > pID->dwTotalSize)
|
|
)
|
|
{
|
|
if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in") ||
|
|
!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/out") ||
|
|
!_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/in") ||
|
|
!_wcsicmp((LPWSTR)pDeviceClassCopy, L"midi/out")
|
|
)
|
|
{
|
|
szStringId1 = WaveDeviceIdToStringId (
|
|
*(DWORD*)((LPBYTE)pID + pID->dwStringOffset),
|
|
(LPWSTR)pDeviceClassCopy);
|
|
if ( szStringId1 )
|
|
{
|
|
dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + sizeof(DWORD);
|
|
if ( dwAvailSize >= (wcslen(szStringId1) + 1) * sizeof(WCHAR) )
|
|
{
|
|
wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 );
|
|
pID->dwStringSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR);
|
|
pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - sizeof(DWORD);
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
|
|
}
|
|
else
|
|
{
|
|
pID->dwNeededSize = (wcslen(szStringId1) + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
ServerFree(szStringId1);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed"));
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
}
|
|
} else if (!_wcsicmp((LPWSTR)pDeviceClassCopy, L"wave/in/out"))
|
|
{
|
|
szStringId1 = WaveDeviceIdToStringId (
|
|
*(DWORD*)((LPBYTE)pID + pID->dwStringOffset),
|
|
L"wave/in");
|
|
szStringId2 = WaveDeviceIdToStringId (
|
|
*( (DWORD*)((LPBYTE)pID + pID->dwStringOffset) + 1 ),
|
|
L"wave/out");
|
|
if ( szStringId1 && szStringId2 )
|
|
{
|
|
dwAvailSize = pID->dwTotalSize - pID->dwUsedSize + 2 * sizeof(DWORD);
|
|
if ( dwAvailSize >= (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR) )
|
|
{
|
|
wcscpy( (LPWSTR)((LPBYTE)pID + pID->dwStringOffset), szStringId1 );
|
|
wcscpy( (LPWSTR)
|
|
((LPBYTE)pID + pID->dwStringOffset +
|
|
(wcslen(szStringId1) + 1) * sizeof(WCHAR)),
|
|
szStringId2
|
|
);
|
|
pID->dwStringSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR);
|
|
pID->dwUsedSize = pID->dwNeededSize = pID->dwUsedSize + pID->dwStringSize - 2 * sizeof(DWORD);
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
|
|
}
|
|
else
|
|
{
|
|
pID->dwNeededSize = (wcslen(szStringId1) + wcslen(szStringId2) + 2) * sizeof(WCHAR);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "PGetIDEx: WaveDeviceIdToStringId failed"));
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
ServerFree(szStringId1);
|
|
ServerFree(szStringId2);
|
|
}
|
|
}
|
|
|
|
ServerFree(pDeviceClassCopy);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetID(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETID_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetID;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if ((pParams->dwDeviceIDTotalSize > dwParamsBufferSize) ||
|
|
|
|
IsBadStringParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwDeviceClassOffset
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETID, // provider func index
|
|
&pfnTSPI_phoneGetID, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetID" // func name
|
|
|
|
)) == 0 || pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
|
|
{
|
|
WCHAR *pszDeviceClass;
|
|
LPVARSTRING pID = (LPVARSTRING) pDataBuf;
|
|
|
|
|
|
//
|
|
// We'll handle the "tapi/phone" class right here rather than
|
|
// burden every single driver with having to support it
|
|
//
|
|
|
|
if (_wcsicmp(
|
|
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset),
|
|
L"tapi/phone"
|
|
|
|
) == 0)
|
|
{
|
|
if (!InitTapiStruct(
|
|
pID,
|
|
pParams->dwDeviceIDTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
pID->dwNeededSize += sizeof (DWORD);
|
|
|
|
if (pID->dwTotalSize >= pID->dwNeededSize)
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
if (!(ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
0
|
|
)))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
try
|
|
{
|
|
*((LPDWORD)(pID + 1)) = ptPhoneClient->ptPhone->dwDeviceID;
|
|
}
|
|
myexcept
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
|
|
if (pParams->lResult == PHONEERR_INVALPHONEHANDLE)
|
|
{
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
pID->dwUsedSize += sizeof (DWORD);
|
|
pID->dwStringFormat = STRINGFORMAT_BINARY;
|
|
pID->dwStringSize = sizeof (DWORD);
|
|
pID->dwStringOffset = sizeof (VARSTRING);
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->lResult = 0;
|
|
pParams->dwDeviceIDOffset = 0;
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
|
|
goto PGetID_epilog;
|
|
}
|
|
else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
|
|
{
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Alloc a temporary buf for the dev class, since we'll be using
|
|
// the existing buffer for output
|
|
//
|
|
|
|
{
|
|
UINT nStringSize;
|
|
|
|
nStringSize = sizeof(WCHAR) * (1 + wcslen((PWSTR)(pDataBuf +
|
|
pParams->dwDeviceClassOffset)));
|
|
|
|
if (0 == nStringSize)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPARAM;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
|
|
if (!(pszDeviceClass = (WCHAR *) ServerAlloc(nStringSize) ))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
}
|
|
|
|
wcscpy(
|
|
pszDeviceClass,
|
|
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)
|
|
);
|
|
|
|
|
|
if (!InitTapiStruct(
|
|
pID,
|
|
pParams->dwDeviceIDTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
ServerFree (pszDeviceClass);
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
if ((pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneGetID,
|
|
"phoneGetID",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) pID,
|
|
(ULONG_PTR) pszDeviceClass,
|
|
(ULONG_PTR) (IS_REMOTE_CLIENT (ptClient) ?
|
|
(HANDLE) -1 : ptClient->hProcess)
|
|
|
|
)) == 0)
|
|
{
|
|
|
|
#if TELE_SERVER
|
|
//
|
|
// If
|
|
// this is a server &
|
|
// client doesn't have admin privileges &
|
|
// the specified device class == "tapi/line" &
|
|
// the dwUsedSize indicates that a line id was
|
|
// (likely) copied to the buffer
|
|
// then
|
|
// try to map the retrieved line device id back
|
|
// to one that makes sense to the client (and
|
|
// fail the request if there's no mapping)
|
|
//
|
|
|
|
if (IS_REMOTE_CLIENT(ptClient) &&
|
|
(_wcsicmp (pszDeviceClass, L"tapi/line") == 0) &&
|
|
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) &&
|
|
(pID->dwUsedSize >= (sizeof (*pID) + sizeof (DWORD))))
|
|
{
|
|
DWORD i;
|
|
LPDWORD pdwLineID = (LPDWORD)
|
|
(((LPBYTE) pID) + pID->dwStringOffset);
|
|
|
|
|
|
for (i = 0; i < ptClient->dwLineDevices; i++)
|
|
{
|
|
if (*pdwLineID == ptClient->pLineDevices[i])
|
|
{
|
|
*pdwLineID = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= ptClient->dwLineDevices)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
}
|
|
}
|
|
#endif
|
|
//
|
|
// Indicate offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwDeviceIDOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
|
|
}
|
|
|
|
ServerFree (pszDeviceClass);
|
|
}
|
|
|
|
PGetID_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetID"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetLamp(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETLAMP_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetLamp;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETLAMP, // provider func index
|
|
&pfnTSPI_phoneGetLamp, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetLamp" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetLamp,
|
|
"phoneGetLamp",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(ULONG_PTR) &pParams->dwLampMode
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETLAMP_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetLamp"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetRing(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETRING_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetRing;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETRING, // provider func index
|
|
&pfnTSPI_phoneGetRing, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetRing" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetRing,
|
|
"phoneGetRing",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) &pParams->dwRingMode,
|
|
(ULONG_PTR) &pParams->dwVolume
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETRING_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetRing"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetStatus(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETSTATUS_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetStatus;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (pParams->dwPhoneStatusTotalSize > dwParamsBufferSize)
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETSTATUS, // provider func index
|
|
&pfnTSPI_phoneGetStatus, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetStatus" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwAPIVersion, dwSPIVersion, dwTotalSize,
|
|
dwFixedSizeClient, dwFixedSizeSP;
|
|
LPPHONESTATUS pStatus = (LPPHONESTATUS) pDataBuf,
|
|
pStatus2 = (LPPHONESTATUS) NULL;
|
|
|
|
|
|
if (!(ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
0
|
|
)))
|
|
{
|
|
pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
|
|
// since ReferenceObject failed, no point
|
|
// in dereferencing.
|
|
goto PGetStatus_epilog;
|
|
}
|
|
|
|
//
|
|
// Safely retrieve the API & SPI versions
|
|
//
|
|
|
|
if (GetPhoneVersions(
|
|
pParams->hPhone,
|
|
&dwAPIVersion,
|
|
&dwSPIVersion
|
|
|
|
) != 0)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PGetStatus_dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure for the specified API
|
|
// version, verify client's buffer is big enough
|
|
//
|
|
|
|
dwTotalSize = pParams->dwPhoneStatusTotalSize;
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
case TAPI_VERSION1_4:
|
|
|
|
dwFixedSizeClient = 100; // 25 * sizeof (DWORD)
|
|
break;
|
|
|
|
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeClient = sizeof (PHONESTATUS);
|
|
break;
|
|
}
|
|
|
|
if (dwTotalSize < dwFixedSizeClient)
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetStatus_dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure expected by the SP
|
|
//
|
|
|
|
switch (dwSPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
case TAPI_VERSION1_4:
|
|
|
|
dwFixedSizeSP = 100; // 25 * sizeof (DWORD)
|
|
break;
|
|
|
|
default: // (fix ppc build wrn) case TAPI_VERSION_CURRENT:
|
|
|
|
dwFixedSizeSP = sizeof (PHONESTATUS);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// If the client's buffer is < the fixed size of that expected by
|
|
// the SP (client is lower version than SP) then allocate an
|
|
// intermediate buffer
|
|
//
|
|
|
|
if (dwTotalSize < dwFixedSizeSP)
|
|
{
|
|
if (!(pStatus2 = ServerAlloc (dwFixedSizeSP)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PGetStatus_dereference;
|
|
}
|
|
|
|
pStatus = pStatus2;
|
|
dwTotalSize = dwFixedSizeSP;
|
|
}
|
|
|
|
|
|
InitTapiStruct(
|
|
pStatus,
|
|
dwTotalSize,
|
|
dwFixedSizeSP,
|
|
(pStatus2 == NULL ? TRUE : FALSE)
|
|
);
|
|
|
|
if ((pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneGetStatus,
|
|
"phoneGetStatus",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(ULONG_PTR) pStatus
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwNeededSize = 0, dwAlign = 0;
|
|
PTPHONEAPP ptPhoneApp;
|
|
PTPHONE ptPhone;
|
|
PTPHONECLIENT ptPhClnt;
|
|
WCHAR *pAppName;
|
|
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
//
|
|
// Add the fields we're responsible for
|
|
//
|
|
|
|
try
|
|
{
|
|
ptPhone = ptPhoneClient->ptPhone;
|
|
|
|
pStatus->dwNumOwners = ptPhone->dwNumOwners;
|
|
pStatus->dwNumMonitors = ptPhone->dwNumMonitors;
|
|
|
|
if (0 != pStatus->dwUsedSize % 2) // 2 is sizeof(WCHAR)
|
|
{
|
|
// make sure that the owner name will always be aligned
|
|
// on a WCHAR boundary.
|
|
dwAlign = 1;
|
|
}
|
|
|
|
// Initialize fields.
|
|
pStatus->dwOwnerNameSize = 0;
|
|
pStatus->dwOwnerNameOffset = 0;
|
|
|
|
if (0 != ptPhone->dwNumOwners)
|
|
{
|
|
for (ptPhClnt = ptPhone->ptPhoneClients; NULL != ptPhClnt; ptPhClnt = ptPhClnt->pNextSametPhone)
|
|
{
|
|
if (PHONEPRIVILEGE_OWNER == ptPhClnt->dwPrivilege)
|
|
{
|
|
ptPhoneApp = ptPhClnt->ptPhoneApp;
|
|
if (0 < ptPhoneApp->dwFriendlyNameSize &&
|
|
NULL != ptPhoneApp->pszFriendlyName)
|
|
{
|
|
dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign;
|
|
pAppName = ptPhoneApp->pszFriendlyName;
|
|
}
|
|
else if (0 < ptPhoneApp->dwModuleNameSize &&
|
|
NULL != ptPhoneApp->pszModuleName)
|
|
{
|
|
dwNeededSize = ptPhoneApp->dwFriendlyNameSize + dwAlign;
|
|
pAppName = ptPhoneApp->pszFriendlyName;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
pStatus->dwNeededSize += dwNeededSize;
|
|
|
|
if (dwNeededSize <= pStatus->dwTotalSize - pStatus->dwUsedSize)
|
|
{
|
|
pStatus->dwOwnerNameSize = dwNeededSize - dwAlign;
|
|
pStatus->dwOwnerNameOffset = pStatus->dwUsedSize + dwAlign;
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pStatus) + pStatus->dwOwnerNameOffset,
|
|
pAppName,
|
|
dwNeededSize-dwAlign
|
|
);
|
|
|
|
if (ptPhoneApp->dwKey == TPHONEAPP_KEY)
|
|
{
|
|
pStatus->dwUsedSize += dwNeededSize;
|
|
}
|
|
else
|
|
{
|
|
pStatus->dwOwnerNameSize = 0;
|
|
pStatus->dwOwnerNameOffset = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PGetStatus_dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// Munge fields where appropriate for old apps (don't want to
|
|
// pass back flags that they won't understand)
|
|
//
|
|
|
|
|
|
//
|
|
// If an intermediate buffer was used then copy the bits back
|
|
// to the the original buffer, & free the intermediate buffer.
|
|
// Also reset the dwUsedSize field to the fixed size of the
|
|
// structure for the specifed version, since any data in the
|
|
// variable portion is garbage as far as the client is concerned.
|
|
//
|
|
|
|
if (pStatus == pStatus2)
|
|
{
|
|
pStatus = (LPPHONESTATUS) pDataBuf;
|
|
|
|
CopyMemory (pStatus, pStatus2, dwFixedSizeClient);
|
|
|
|
ServerFree (pStatus2);
|
|
|
|
pStatus->dwTotalSize = pParams->dwPhoneStatusTotalSize;
|
|
pStatus->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->dwPhoneStatusOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pStatus->dwUsedSize;
|
|
}
|
|
|
|
PGetStatus_dereference:
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
}
|
|
|
|
PGetStatus_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetStatus"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetStatusMessages(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETSTATUSMESSAGES_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
if ((ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
0
|
|
)))
|
|
{
|
|
if (ptPhoneClient->ptClient == ptClient)
|
|
{
|
|
pParams->dwPhoneStates = ptPhoneClient->dwPhoneStates;
|
|
pParams->dwButtonModes = ptPhoneClient->dwButtonModes;
|
|
pParams->dwButtonStates = ptPhoneClient->dwButtonStates;
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEGETSTATUSMESSAGES_PARAMS);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALPHONEHANDLE : PHONEERR_UNINITIALIZED);
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"phoneGetStatusMessages: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"phoneGetStatusMessages: exit, result=x%x",
|
|
pParams->lResult
|
|
));
|
|
#endif
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetVolume(
|
|
PTCLIENT ptClient,
|
|
PPHONEGETVOLUME_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetVolume;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONEGETVOLUME, // provider func index
|
|
&pfnTSPI_phoneGetVolume, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"GetVolume" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
|
|
(pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALHOOKSWITCHDEV;
|
|
}
|
|
else
|
|
{
|
|
if ((pParams->lResult = CallSP3(
|
|
pfnTSPI_phoneGetVolume,
|
|
"phoneGetVolume",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(ULONG_PTR) &pParams->dwVolume
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETVOLUME_PARAMS);
|
|
}
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetVolume"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PInitialize(
|
|
PTCLIENT ptClient,
|
|
PPHONEINITIALIZE_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
DWORD dwFriendlyNameSize, dwModuleNameSize;
|
|
PTPHONEAPP ptPhoneApp;
|
|
BOOL bInitClient = FALSE;
|
|
|
|
LOG((TL_TRACE, "PInitialize - enter. dwParamsBufferSize %lx, ptClient %p", dwParamsBufferSize, ptClient));
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (IsBadStringParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwFriendlyNameOffset
|
|
) ||
|
|
|
|
IsBadStringParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwModuleNameOffset
|
|
))
|
|
{
|
|
LOG((TL_ERROR, "PInitialize - error1."));
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Alloc & init a new tPhoneApp
|
|
//
|
|
|
|
dwFriendlyNameSize = sizeof(WCHAR) * (1 + lstrlenW(
|
|
(PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset))
|
|
);
|
|
|
|
dwModuleNameSize = sizeof(WCHAR) * (1 + lstrlenW(
|
|
(PWSTR)(pDataBuf + pParams->dwModuleNameOffset))
|
|
);
|
|
|
|
if (!(ptPhoneApp = ServerAlloc(
|
|
sizeof (TPHONEAPP) +
|
|
dwFriendlyNameSize +
|
|
dwModuleNameSize
|
|
)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PInitialize_return;
|
|
}
|
|
|
|
if (!(ptPhoneApp->hPhoneApp = (HPHONEAPP) NewObject(
|
|
ghHandleTable,
|
|
ptPhoneApp,
|
|
NULL
|
|
)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
ServerFree (ptPhoneApp);
|
|
goto PInitialize_return;
|
|
}
|
|
|
|
ptPhoneApp->dwKey = TPHONEAPP_KEY;
|
|
ptPhoneApp->ptClient = ptClient;
|
|
ptPhoneApp->InitContext = pParams->InitContext;
|
|
ptPhoneApp->dwAPIVersion = pParams->dwAPIVersion;
|
|
|
|
ptPhoneApp->pszFriendlyName = (WCHAR *) (ptPhoneApp + 1);
|
|
ptPhoneApp->dwFriendlyNameSize = dwFriendlyNameSize;
|
|
|
|
wcscpy(
|
|
ptPhoneApp->pszFriendlyName,
|
|
(PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)
|
|
);
|
|
|
|
ptPhoneApp->pszModuleName = (PWSTR)((BYTE *) (ptPhoneApp + 1) + dwFriendlyNameSize);
|
|
ptPhoneApp->dwModuleNameSize = dwModuleNameSize;
|
|
|
|
wcscpy(
|
|
ptPhoneApp->pszModuleName,
|
|
(PWSTR)(pDataBuf + pParams->dwModuleNameOffset)
|
|
);
|
|
|
|
|
|
//
|
|
// Safely insert new tPhoneApp at front of tClient's tPhoneApp list
|
|
//
|
|
|
|
if (ptClient->ptLineApps == NULL)
|
|
{
|
|
bInitClient = TRUE;
|
|
}
|
|
|
|
|
|
if (WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0)
|
|
{
|
|
FillMemory (
|
|
ptPhoneApp->adwEventSubMasks,
|
|
sizeof(DWORD) * EM_NUM_MASKS,
|
|
(BYTE) 0xff
|
|
);
|
|
}
|
|
else
|
|
{
|
|
CopyMemory (
|
|
ptPhoneApp->adwEventSubMasks,
|
|
ptClient->adwEventSubMasks,
|
|
sizeof(DWORD) * EM_NUM_MASKS
|
|
);
|
|
}
|
|
|
|
if ((ptPhoneApp->pNext = ptClient->ptPhoneApps))
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp;
|
|
}
|
|
|
|
ptClient->ptPhoneApps = ptPhoneApp;
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "PInitialize - error2."));
|
|
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
goto PInitialize_error1;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if global reinit flag set
|
|
//
|
|
|
|
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
|
|
{
|
|
pParams->lResult = PHONEERR_REINIT;
|
|
goto PInitialize_error2;
|
|
}
|
|
|
|
|
|
//
|
|
// See if we need to go thru init
|
|
//
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
if ((TapiGlobals.dwNumLineInits == 0) &&
|
|
(TapiGlobals.dwNumPhoneInits == 0) &&
|
|
!gbServerInited)
|
|
{
|
|
if ((pParams->lResult = ServerInit(FALSE)) != 0)
|
|
{
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
goto PInitialize_error2;
|
|
}
|
|
gbServerInited = TRUE;
|
|
}
|
|
|
|
|
|
|
|
#if TELE_SERVER
|
|
if (bInitClient)
|
|
{
|
|
if (pParams->lResult = InitializeClient (ptClient))
|
|
{
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
goto PInitialize_error2;
|
|
}
|
|
}
|
|
#else
|
|
pParams->lResult = 0; // That's what happens if it's not a server...
|
|
#endif
|
|
|
|
|
|
//
|
|
// Fill in the return values
|
|
//
|
|
|
|
pParams->hPhoneApp = ptPhoneApp->hPhoneApp;
|
|
pParams->dwNumDevs = TapiGlobals.dwNumPhones;
|
|
|
|
|
|
#if TELE_SERVER
|
|
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
|
|
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
|
|
{
|
|
pParams->dwNumDevs = ptClient->dwPhoneDevices;
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Increment total num phone inits
|
|
//
|
|
|
|
TapiGlobals.dwNumPhoneInits++;
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEINITIALIZE_PARAMS);
|
|
|
|
TapiLeaveCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
goto PInitialize_return;
|
|
|
|
PInitialize_error2:
|
|
|
|
if (WaitForExclusiveClientAccess (ptClient))
|
|
{
|
|
if (ptPhoneApp->pNext)
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
|
|
}
|
|
|
|
if (ptPhoneApp->pPrev)
|
|
{
|
|
ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
|
|
}
|
|
else
|
|
{
|
|
ptClient->ptPhoneApps = ptPhoneApp->pNext;
|
|
}
|
|
|
|
UNLOCKTCLIENT (ptClient);
|
|
}
|
|
|
|
PInitialize_error1:
|
|
|
|
DereferenceObject (ghHandleTable, ptPhoneApp->hPhoneApp, 1);
|
|
|
|
PInitialize_return:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"phoneInitialize: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"phoneInitialize: exit, result=x%x",
|
|
pParams->lResult
|
|
));
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PNegotiateAPIVersion(
|
|
PTCLIENT ptClient,
|
|
PPHONENEGOTIATEAPIVERSION_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
//
|
|
// Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
|
|
//
|
|
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (dwParamsBufferSize < sizeof (PHONEEXTENSIONID))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if (TapiGlobals.dwNumPhoneInits == 0)
|
|
{
|
|
pParams->lResult = PHONEERR_UNINITIALIZED;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
|
|
#if TELE_SERVER
|
|
|
|
if ((TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) &&
|
|
!IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR))
|
|
{
|
|
try
|
|
{
|
|
if (dwDeviceID >= ptClient->dwPhoneDevices)
|
|
{
|
|
pParams->lResult = PHONEERR_BADDEVICEID;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
dwDeviceID = ptClient->pPhoneDevices[dwDeviceID];
|
|
}
|
|
myexcept
|
|
{
|
|
LOG((TL_ERROR, "ptClient excepted in PhoneNegotiateAPIVersion"));
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
if (dwDeviceID < TapiGlobals.dwNumPhones)
|
|
{
|
|
DWORD dwAPIHighVersion = pParams->dwAPIHighVersion,
|
|
dwAPILowVersion = pParams->dwAPILowVersion,
|
|
dwHighestValidAPIVersion;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
if (!(ptPhoneApp = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhoneApp,
|
|
TPHONEAPP_KEY
|
|
)))
|
|
{
|
|
pParams->lResult = (TapiGlobals.dwNumPhoneInits ?
|
|
PHONEERR_INVALAPPHANDLE : PHONEERR_UNINITIALIZED);
|
|
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Do a minimax test on the specified lo/hi values
|
|
//
|
|
|
|
if ((dwAPILowVersion > dwAPIHighVersion) ||
|
|
(dwAPILowVersion > TAPI_VERSION_CURRENT) ||
|
|
(dwAPIHighVersion < TAPI_VERSION1_0))
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the highest valid API version given the lo/hi values.
|
|
// Since valid vers aren't consecutive we need to check for
|
|
// errors that our minimax test missed.
|
|
//
|
|
|
|
if (dwAPIHighVersion < TAPI_VERSION_CURRENT)
|
|
{
|
|
if ((dwAPIHighVersion >= TAPI_VERSION3_0) &&
|
|
(dwAPILowVersion <= TAPI_VERSION3_0))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION3_0;
|
|
}
|
|
else if ((dwAPIHighVersion >= TAPI_VERSION2_2) &&
|
|
(dwAPILowVersion <= TAPI_VERSION2_2))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION2_2;
|
|
}
|
|
else if ((dwAPIHighVersion >= TAPI_VERSION2_1) &&
|
|
(dwAPILowVersion <= TAPI_VERSION2_1))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION2_1;
|
|
}
|
|
else if ((dwAPIHighVersion >= TAPI_VERSION2_0) &&
|
|
(dwAPILowVersion <= TAPI_VERSION2_0))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION2_0;
|
|
}
|
|
else if ((dwAPIHighVersion >= TAPI_VERSION1_4) &&
|
|
(dwAPILowVersion <= TAPI_VERSION1_4))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION1_4;
|
|
}
|
|
else if ((dwAPIHighVersion >= TAPI_VERSION1_0) &&
|
|
(dwAPILowVersion <= TAPI_VERSION1_0))
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION1_0;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, " Incompatible version"));
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION_CURRENT;
|
|
}
|
|
|
|
|
|
//
|
|
// WARNING!!! WARNING!!! WARNING!!! WARNING!!!
|
|
// This code overwrites ptPhoneApp and later invalidates it.
|
|
// Do NOT use ptPhoneApp after the UNLOCKTPHONEAPP call.
|
|
//
|
|
|
|
if (WaitForExclusivePhoneAppAccess(
|
|
pParams->hPhoneApp,
|
|
ptClient
|
|
))
|
|
{
|
|
|
|
//
|
|
// Is this app trying to negotiate something valid?
|
|
//
|
|
// If an app has called phoneInitalize (as opposed to
|
|
// phoneInitializeEx), we'll clamp the max APIVersion they can
|
|
// negotiate to 1.4.
|
|
//
|
|
if ( ptPhoneApp->dwAPIVersion < TAPI_VERSION2_0 )
|
|
{
|
|
dwHighestValidAPIVersion =
|
|
(dwHighestValidAPIVersion >= TAPI_VERSION1_4) ?
|
|
TAPI_VERSION1_4 : TAPI_VERSION1_0;
|
|
}
|
|
|
|
|
|
//
|
|
// Save the highest valid API version the client says it supports
|
|
// (we need this for determining which msgs to send to it)
|
|
//
|
|
|
|
if (dwHighestValidAPIVersion > ptPhoneApp->dwAPIVersion)
|
|
{
|
|
ptPhoneApp->dwAPIVersion = dwHighestValidAPIVersion;
|
|
}
|
|
|
|
UNLOCKTPHONEAPP(ptPhoneApp);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALAPPHANDLE;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// See if there's a valid match with the SPI ver
|
|
//
|
|
|
|
{
|
|
DWORD dwSPIVersion;
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
|
|
|
|
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
|
|
dwSPIVersion = pLookupEntry->dwSPIVersion;
|
|
|
|
if (pLookupEntry->bRemoved)
|
|
{
|
|
LOG((TL_ERROR, " phone removed..."));
|
|
pParams->lResult = PHONEERR_NODEVICE;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
|
|
if (pLookupEntry->ptProvider == NULL)
|
|
{
|
|
LOG((TL_ERROR, " Provider == NULL"));
|
|
pParams->lResult = PHONEERR_NODRIVER;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
|
|
if (dwAPILowVersion <= dwSPIVersion)
|
|
{
|
|
pParams->dwAPIVersion =
|
|
(dwHighestValidAPIVersion > dwSPIVersion ?
|
|
dwSPIVersion : dwHighestValidAPIVersion);
|
|
|
|
|
|
//
|
|
// Retrieve ext id (indicate no exts if GetExtID not exported)
|
|
//
|
|
|
|
if (pLookupEntry->ptProvider->apfn[SP_PHONEGETEXTENSIONID])
|
|
{
|
|
if ((pParams->lResult = CallSP3(
|
|
pLookupEntry->ptProvider->
|
|
apfn[SP_PHONEGETEXTENSIONID],
|
|
"phoneGetExtensionID",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) dwSPIVersion,
|
|
(ULONG_PTR) pDataBuf
|
|
|
|
)) != 0)
|
|
{
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FillMemory (pDataBuf, sizeof (PHONEEXTENSIONID), 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, " API version too high"));
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateAPIVersion_dereference;
|
|
}
|
|
}
|
|
|
|
pParams->dwExtensionIDOffset = 0;
|
|
pParams->dwSize = sizeof (PHONEEXTENSIONID);
|
|
|
|
LOG((TL_INFO, " ExtensionID0=x%08lx", *(LPDWORD)(pDataBuf+0) ));
|
|
LOG((TL_INFO, " ExtensionID1=x%08lx", *(LPDWORD)(pDataBuf+4) ));
|
|
LOG((TL_INFO, " ExtensionID2=x%08lx", *(LPDWORD)(pDataBuf+8) ));
|
|
LOG((TL_INFO, " ExtensionID3=x%08lx", *(LPDWORD)(pDataBuf+12) ));
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEEXTENSIONID) + sizeof (TAPI32_MSG);
|
|
|
|
PNegotiateAPIVersion_dereference:
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhoneApp, 1);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_BADDEVICEID;
|
|
}
|
|
|
|
PNegotiateAPIVersion_exit:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"phoneNegotiateAPIVersion: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"phoneNegotiateAPIVersion: exit, result=x%x",
|
|
pParams->lResult
|
|
));
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PNegotiateExtVersion(
|
|
PTCLIENT ptClient,
|
|
PPHONENEGOTIATEEXTVERSION_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneNegotiateExtVersion;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
DEVICE_ID, // widget type
|
|
(DWORD) pParams->hPhoneApp, // client widget handle
|
|
NULL, // provider widget handle
|
|
&dwDeviceID, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONENEGOTIATEEXTVERSION,// provider func index
|
|
&pfnTSPI_phoneNegotiateExtVersion, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"NegotiateExtVersion" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwSPIVersion = (GetPhoneLookupEntry(dwDeviceID))->dwSPIVersion;
|
|
|
|
|
|
if (!IsAPIVersionInRange(
|
|
pParams->dwAPIVersion,
|
|
dwSPIVersion
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateExtVersion_epilog;
|
|
}
|
|
|
|
if ((pParams->lResult = CallSP5(
|
|
pfnTSPI_phoneNegotiateExtVersion,
|
|
"phoneNegotiateExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) dwSPIVersion,
|
|
(DWORD) pParams->dwExtLowVersion,
|
|
(DWORD) pParams->dwExtHighVersion,
|
|
(ULONG_PTR) &pParams->dwExtVersion
|
|
|
|
)) == 0)
|
|
{
|
|
if (pParams->dwExtVersion == 0)
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
|
|
}
|
|
else
|
|
{
|
|
*pdwNumBytesReturned = sizeof(PHONENEGOTIATEEXTVERSION_PARAMS);
|
|
}
|
|
}
|
|
}
|
|
|
|
PNegotiateExtVersion_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"NegotiateExtVersion"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
POpen(
|
|
PTCLIENT ptClient,
|
|
PPHONEOPEN_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex,
|
|
bOpenedtPhone = FALSE,
|
|
bReleasetPhoneMutex = FALSE;
|
|
LONG lResult;
|
|
DWORD dwDeviceID = pParams->dwDeviceID, dwNumMonitors;
|
|
HANDLE hMutex;
|
|
PTPHONE ptPhone = NULL;
|
|
PTPHONECLIENT ptPhoneClient = NULL;
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
HANDLE hLookupEntryMutex = NULL;
|
|
|
|
|
|
if ((lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
DEVICE_ID, // widget type
|
|
(DWORD) pParams->hPhoneApp, // client widget handle
|
|
NULL, // provider widget handle
|
|
&dwDeviceID, // privileges or device ID
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
0, // provider func index
|
|
NULL, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"Open" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwPrivilege = pParams->dwPrivilege,
|
|
dwExtVersion = pParams->dwExtVersion;
|
|
PTPROVIDER ptProvider;
|
|
BOOL bDuplicateOK = FALSE;
|
|
|
|
|
|
//
|
|
// Check if the global reinit flag is set
|
|
//
|
|
|
|
if (TapiGlobals.dwFlags & TAPIGLOBALS_REINIT)
|
|
{
|
|
lResult = PHONEERR_REINIT;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Validate params
|
|
//
|
|
|
|
if ((dwPrivilege != PHONEPRIVILEGE_MONITOR) &&
|
|
(dwPrivilege != PHONEPRIVILEGE_OWNER))
|
|
{
|
|
lResult = PHONEERR_INVALPRIVILEGE;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
|
|
|
|
TapiEnterCriticalSection (&TapiGlobals.CritSec);
|
|
|
|
if ( pLookupEntry->hMutex )
|
|
{
|
|
bDuplicateOK = DuplicateHandle(
|
|
TapiGlobals.hProcess,
|
|
pLookupEntry->hMutex,
|
|
TapiGlobals.hProcess,
|
|
&hLookupEntryMutex,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
}
|
|
|
|
TapiLeaveCriticalSection(&TapiGlobals.CritSec);
|
|
|
|
if ( !bDuplicateOK )
|
|
{
|
|
LOG((TL_ERROR, "DuplicateHandle failed!"));
|
|
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
if (!IsAPIVersionInRange(
|
|
pParams->dwAPIVersion,
|
|
pLookupEntry->dwSPIVersion
|
|
))
|
|
{
|
|
lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptProvider = pLookupEntry->ptProvider;
|
|
|
|
|
|
//
|
|
// Create & init a tPhoneClient & associated resources
|
|
//
|
|
|
|
if (!(ptPhoneClient = ServerAlloc (sizeof(TPHONECLIENT))))
|
|
{
|
|
lResult = PHONEERR_NOMEM;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
if (!(ptPhoneClient->hPhone = (HPHONE) NewObject(
|
|
ghHandleTable,
|
|
ptPhoneClient,
|
|
0
|
|
)))
|
|
{
|
|
ptPhoneClient = NULL;
|
|
ServerFree (ptPhoneClient);
|
|
lResult = PHONEERR_NOMEM;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptPhoneClient->ptClient = ptClient;
|
|
ptPhoneClient->hRemotePhone = (pParams->hRemotePhone ?
|
|
(DWORD) pParams->hRemotePhone : ptPhoneClient->hPhone);
|
|
ptPhoneClient->dwAPIVersion = pParams->dwAPIVersion;
|
|
ptPhoneClient->dwPrivilege = pParams->dwPrivilege;
|
|
ptPhoneClient->OpenContext = pParams->OpenContext;
|
|
|
|
//
|
|
// Grab the tPhone's mutex, then start doing the open
|
|
//
|
|
|
|
POpen_waitForMutex:
|
|
|
|
if (WaitForSingleObject (hLookupEntryMutex, INFINITE)
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
LOG((TL_ERROR, "WaitForSingleObject failed!"));
|
|
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
bReleasetPhoneMutex = TRUE;
|
|
|
|
|
|
//
|
|
// If the tPhone is in the process of being destroyed then spin
|
|
// until it's been completely destroyed (DestroytPhone() will
|
|
// NULLify pLookupEntry->ptPhone when it's finished). Make sure
|
|
// to release the mutex while sleeping so we don't block
|
|
// DestroytPhone.
|
|
//
|
|
|
|
try
|
|
{
|
|
while (pLookupEntry->ptPhone &&
|
|
pLookupEntry->ptPhone->dwKey != TPHONE_KEY)
|
|
{
|
|
ReleaseMutex (hLookupEntryMutex);
|
|
Sleep (0);
|
|
goto POpen_waitForMutex;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
// If here pLookupEntry->ptPhone was NULLified, safe to continue
|
|
}
|
|
|
|
|
|
//
|
|
// Validate ext ver as appropriate
|
|
//
|
|
|
|
if (dwExtVersion != 0 &&
|
|
(!IsValidPhoneExtVersion (dwDeviceID, dwExtVersion) ||
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL))
|
|
{
|
|
lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Check for exclusive ownership as appropriate
|
|
//
|
|
|
|
ptPhone = pLookupEntry->ptPhone;
|
|
|
|
if (dwPrivilege == PHONEPRIVILEGE_OWNER &&
|
|
ptPhone &&
|
|
(ptPhone->dwNumOwners != 0)
|
|
)
|
|
{
|
|
lResult = PHONEERR_INUSE;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
if (ptPhone == NULL)
|
|
{
|
|
if (!(ptPhone = ServerAlloc (sizeof(TPHONE))))
|
|
{
|
|
lResult = PHONEERR_NOMEM;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
if (!(ptPhone->hPhone = (HPHONE) NewObject(
|
|
ghHandleTable,
|
|
(LPVOID) ptPhone,
|
|
NULL
|
|
)))
|
|
{
|
|
ServerFree (ptPhone);
|
|
lResult = PHONEERR_NOMEM;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptPhone->dwKey = TINCOMPLETEPHONE_KEY;
|
|
ptPhone->hMutex = pLookupEntry->hMutex;
|
|
ptPhone->ptProvider = ptProvider;
|
|
ptPhone->dwDeviceID = dwDeviceID;
|
|
ptPhone->dwSPIVersion = pLookupEntry->dwSPIVersion;
|
|
|
|
bOpenedtPhone = TRUE;
|
|
|
|
{
|
|
//
|
|
// Hack Alert!
|
|
//
|
|
// We need to pass the ext version through to
|
|
// remote sp, so we make this a special case
|
|
//
|
|
|
|
ULONG_PTR aParams[2];
|
|
ULONG_PTR param;
|
|
|
|
|
|
if (ptProvider == pRemoteSP)
|
|
{
|
|
aParams[0] = (ULONG_PTR) ptPhone;
|
|
aParams[1] = dwExtVersion;
|
|
|
|
param = (ULONG_PTR) aParams;
|
|
}
|
|
else
|
|
{
|
|
param = (ULONG_PTR) ptPhone;
|
|
}
|
|
|
|
if (ptProvider->apfn[SP_PHONEOPEN] == NULL)
|
|
{
|
|
lResult = PHONEERR_OPERATIONUNAVAIL;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
if ((lResult = CallSP5(
|
|
ptProvider->apfn[SP_PHONEOPEN],
|
|
"phoneOpen",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(ULONG_PTR) param,
|
|
(ULONG_PTR) &ptPhone->hdPhone,
|
|
(DWORD) pLookupEntry->dwSPIVersion,
|
|
(ULONG_PTR) PhoneEventProcSP
|
|
|
|
)) != 0)
|
|
{
|
|
goto POpen_cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
ptPhoneClient->ptPhone = ptPhone;
|
|
|
|
|
|
//
|
|
// If the client has specified a non-zero ext version then
|
|
// ask the driver to enable it and/or increment the ext
|
|
// version count.
|
|
//
|
|
|
|
if (dwExtVersion)
|
|
{
|
|
if (ptPhone->dwExtVersionCount == 0)
|
|
{
|
|
if (ptProvider != pRemoteSP &&
|
|
((ptProvider->apfn[SP_PHONESELECTEXTVERSION] == NULL) ||
|
|
(lResult = CallSP2(
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) ptPhone->hdPhone,
|
|
(DWORD) dwExtVersion
|
|
|
|
)) != 0))
|
|
{
|
|
if (bOpenedtPhone && ptProvider->apfn[SP_PHONECLOSE])
|
|
{
|
|
CallSP1(
|
|
ptProvider->apfn[SP_PHONECLOSE],
|
|
"phoneClose",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) ptPhone->hdPhone
|
|
);
|
|
}
|
|
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptPhone->dwExtVersion = dwExtVersion;
|
|
}
|
|
|
|
ptPhoneClient->dwExtVersion = dwExtVersion;
|
|
ptPhone->dwExtVersionCount++;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
if (dwPrivilege == PHONEPRIVILEGE_OWNER)
|
|
{
|
|
ptPhone->dwNumOwners++;
|
|
}
|
|
else
|
|
{
|
|
ptPhone->dwNumMonitors++;
|
|
dwNumMonitors = ptPhone->dwNumMonitors;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the tPhoneClient to the tPhone's list
|
|
//
|
|
|
|
if ((ptPhoneClient->pNextSametPhone = ptPhone->ptPhoneClients))
|
|
{
|
|
ptPhoneClient->pNextSametPhone->pPrevSametPhone = ptPhoneClient;
|
|
}
|
|
|
|
ptPhone->ptPhoneClients = ptPhoneClient;
|
|
|
|
if (bOpenedtPhone)
|
|
{
|
|
pLookupEntry->ptPhone = ptPhone;
|
|
ptPhone->dwKey = TPHONE_KEY;
|
|
}
|
|
|
|
ReleaseMutex (hLookupEntryMutex);
|
|
|
|
bReleasetPhoneMutex = FALSE;
|
|
|
|
|
|
//
|
|
// Safely add the new tPhoneClient to the tPhoneApp's list
|
|
//
|
|
|
|
{
|
|
HANDLE hMutex;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
if ((ptPhoneApp = WaitForExclusivePhoneAppAccess(
|
|
pParams->hPhoneApp,
|
|
ptClient
|
|
)))
|
|
{
|
|
|
|
if (ptPhoneApp->dwAPIVersion <= TAPI_VERSION3_0)
|
|
{
|
|
FillMemory (
|
|
ptPhoneClient->adwEventSubMasks,
|
|
sizeof(DWORD) * EM_NUM_MASKS,
|
|
(BYTE) 0xff
|
|
);
|
|
}
|
|
else
|
|
{
|
|
CopyMemory (
|
|
ptPhoneClient->adwEventSubMasks,
|
|
ptPhoneApp->adwEventSubMasks,
|
|
sizeof(DWORD) * EM_NUM_MASKS
|
|
);
|
|
}
|
|
|
|
if ((ptPhoneClient->pNextSametPhoneApp =
|
|
ptPhoneApp->ptPhoneClients))
|
|
{
|
|
ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
|
|
ptPhoneClient;
|
|
}
|
|
|
|
ptPhoneApp->ptPhoneClients = ptPhoneClient;
|
|
|
|
ptPhoneClient->ptPhoneApp = ptPhoneApp;
|
|
ptPhoneClient->dwKey = TPHONECLIENT_KEY;
|
|
|
|
|
|
//
|
|
// Fill in the return values
|
|
//
|
|
|
|
pParams->hPhone = ptPhoneClient->hPhone;
|
|
|
|
UNLOCKTPHONEAPP(ptPhoneApp);
|
|
|
|
|
|
//
|
|
// Alert other clients that another open has occured
|
|
//
|
|
|
|
SendMsgToPhoneClients(
|
|
ptPhone,
|
|
ptPhoneClient,
|
|
PHONE_STATE,
|
|
(pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
PHONESTATE_OWNER : PHONESTATE_MONITORS),
|
|
(pParams->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
1 : dwNumMonitors),
|
|
0
|
|
);
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEOPEN_PARAMS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If here the app handle is bad, & we've some special
|
|
// case cleanup to do. Since the tPhoneClient is not
|
|
// in the tPhoneApp's list, we can't simply call
|
|
// DestroytPhone(Client) to clean things up, since the
|
|
// pointer-resetting code will blow up. So we'll
|
|
// grab the tPhone's mutex and explicitly remove the
|
|
// new tPhoneClient from it's list, then do a conditional
|
|
// shutdown on the tPhone (in case any other clients
|
|
// have come along & opened it).
|
|
//
|
|
// Note: keep in mind that a PHONE_CLOSE might be being
|
|
// processed by another thread (if so, it will be
|
|
// spinning on trying to destroy the tPhoneClient
|
|
// which isn't valid at this point)
|
|
//
|
|
|
|
lResult = PHONEERR_INVALAPPHANDLE;
|
|
|
|
WaitForSingleObject (hLookupEntryMutex, INFINITE);
|
|
|
|
//
|
|
// Remove the tpHOneClient from the tLine's list & decrement
|
|
// the number of opens
|
|
//
|
|
|
|
if (ptPhoneClient->pNextSametPhone)
|
|
{
|
|
ptPhoneClient->pNextSametPhone->pPrevSametPhone =
|
|
ptPhoneClient->pPrevSametPhone;
|
|
}
|
|
|
|
if (ptPhoneClient->pPrevSametPhone)
|
|
{
|
|
ptPhoneClient->pPrevSametPhone->pNextSametPhone =
|
|
ptPhoneClient->pNextSametPhone;
|
|
}
|
|
else
|
|
{
|
|
ptPhone->ptPhoneClients = ptPhoneClient->pNextSametPhone;
|
|
}
|
|
|
|
if (dwPrivilege == PHONEPRIVILEGE_OWNER)
|
|
{
|
|
ptPhone->dwNumOwners--;
|
|
}
|
|
else
|
|
{
|
|
ptPhone->dwNumMonitors--;
|
|
}
|
|
|
|
if (dwExtVersion != 0)
|
|
{
|
|
ptPhone->dwExtVersionCount--;
|
|
|
|
if (ptPhone->dwExtVersionCount == 0 &&
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION])
|
|
{
|
|
ptPhone->dwExtVersion = 0;
|
|
|
|
CallSP2(
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) ptPhone->hdPhone,
|
|
(DWORD) 0
|
|
);
|
|
}
|
|
}
|
|
|
|
ReleaseMutex (hLookupEntryMutex);
|
|
|
|
DestroytPhone (ptPhone, FALSE); // conditional destroy
|
|
|
|
bOpenedtPhone = FALSE; // so we don't do err handling below
|
|
}
|
|
}
|
|
|
|
CloseHandle (hLookupEntryMutex);
|
|
}
|
|
|
|
POpen_cleanup:
|
|
|
|
if (bReleasetPhoneMutex)
|
|
{
|
|
ReleaseMutex (hLookupEntryMutex);
|
|
CloseHandle (hLookupEntryMutex);
|
|
}
|
|
|
|
if (lResult != 0)
|
|
{
|
|
if (ptPhoneClient)
|
|
{
|
|
DereferenceObject (ghHandleTable, ptPhoneClient->hPhone, 1);
|
|
}
|
|
|
|
if (bOpenedtPhone)
|
|
{
|
|
DereferenceObject (ghHandleTable, ptPhone->hPhone, 1);
|
|
}
|
|
}
|
|
|
|
pParams->lResult = lResult;
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"Open"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSelectExtVersion(
|
|
PTCLIENT ptClient,
|
|
PPHONESELECTEXTVERSION_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex, bCloseMutex2;
|
|
HANDLE hMutex, hMutex2;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneSelectExtVersion;
|
|
DWORD dwPrivilege = 0;
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESELECTEXTVERSION, // provider func index
|
|
&pfnTSPI_phoneSelectExtVersion, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"SelectExtVersion" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
if ((ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
TPHONECLIENT_KEY
|
|
)))
|
|
{
|
|
if (WaitForExclusivetPhoneAccess(
|
|
ptPhoneClient->ptPhone,
|
|
&hMutex2,
|
|
&bCloseMutex2,
|
|
INFINITE
|
|
))
|
|
{
|
|
if (IsValidPhoneExtVersion(
|
|
ptPhoneClient->ptPhone->dwDeviceID,
|
|
pParams->dwExtVersion
|
|
))
|
|
{
|
|
if (pParams->dwExtVersion)
|
|
{
|
|
if (ptPhoneClient->ptPhone->dwExtVersionCount ||
|
|
|
|
(pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneSelectExtVersion,
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwExtVersion
|
|
|
|
)) == 0)
|
|
{
|
|
ptPhoneClient->dwExtVersion =
|
|
ptPhoneClient->ptPhone->dwExtVersion =
|
|
pParams->dwExtVersion;
|
|
ptPhoneClient->ptPhone->dwExtVersionCount++;
|
|
}
|
|
}
|
|
else if (ptPhoneClient->ptPhone->dwExtVersionCount)
|
|
{
|
|
if (--ptPhoneClient->ptPhone->dwExtVersionCount == 0)
|
|
{
|
|
CallSP2(
|
|
pfnTSPI_phoneSelectExtVersion,
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) 0
|
|
);
|
|
|
|
ptPhoneClient->ptPhone->dwExtVersion = 0;
|
|
}
|
|
|
|
ptPhoneClient->dwExtVersion = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEEXTVERSION;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex2, bCloseMutex2);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"SelectExtVersion"
|
|
);
|
|
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetButtonInfo(
|
|
PTCLIENT ptClient,
|
|
PPHONESETBUTTONINFO_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetButtonInfo;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETBUTTONINFO, // provider func index
|
|
&pfnTSPI_phoneSetButtonInfo,// provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetButtonInfo" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
LONG lResult;
|
|
DWORD dwAPIVersion, dwSPIVersion;
|
|
LPPHONEBUTTONINFO pButtonInfoApp = (LPPHONEBUTTONINFO)
|
|
(pDataBuf + pParams->dwButtonInfoOffset),
|
|
pButtonInfoSP;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (IsBadStructParam(
|
|
dwParamsBufferSize,
|
|
pDataBuf,
|
|
pParams->dwButtonInfoOffset
|
|
))
|
|
{
|
|
lRequestID = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PSetButtonInfo_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Safely get API & SPI version
|
|
//
|
|
|
|
if (GetPhoneVersions(
|
|
pParams->hPhone,
|
|
&dwAPIVersion,
|
|
&dwSPIVersion
|
|
|
|
) != 0)
|
|
{
|
|
lRequestID = PHONEERR_INVALPHONEHANDLE;
|
|
goto PSetButtonInfo_epilog;
|
|
}
|
|
|
|
if ((lResult = ValidateButtonInfo(
|
|
pButtonInfoApp,
|
|
&pButtonInfoSP,
|
|
dwAPIVersion,
|
|
dwSPIVersion
|
|
)))
|
|
{
|
|
lRequestID = lResult;
|
|
goto PSetButtonInfo_epilog;
|
|
}
|
|
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetButtonInfo,
|
|
"phoneSetButtonInfo",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(ULONG_PTR) pButtonInfoSP
|
|
);
|
|
|
|
if (pButtonInfoSP != pButtonInfoApp)
|
|
{
|
|
ServerFree (pButtonInfoSP);
|
|
}
|
|
}
|
|
|
|
PSetButtonInfo_epilog:
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetButtonInfo"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetData(
|
|
PTCLIENT ptClient,
|
|
PPHONESETDATA_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetData;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (ISBADSIZEOFFSET(
|
|
dwParamsBufferSize,
|
|
0,
|
|
pParams->dwSize,
|
|
pParams->dwDataOffset,
|
|
sizeof(DWORD),
|
|
"PSetData",
|
|
"pParams->Data"
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETDATA, // provider func index
|
|
&pfnTSPI_phoneSetData, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetData" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
pParams->lResult = CallSP5(
|
|
pfnTSPI_phoneSetData,
|
|
"phoneSetData",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwDataID,
|
|
(ULONG_PTR) (pParams->dwSize ?
|
|
pDataBuf + pParams->dwDataOffset : NULL),
|
|
(DWORD) pParams->dwSize
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetData"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetDisplay(
|
|
PTCLIENT ptClient,
|
|
PPHONESETDISPLAY_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetDisplay;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
//
|
|
// Verify size/offset/string params given our input buffer/size
|
|
//
|
|
|
|
if (ISBADSIZEOFFSET(
|
|
dwParamsBufferSize,
|
|
0,
|
|
pParams->dwSize,
|
|
pParams->dwDisplayOffset,
|
|
sizeof(DWORD),
|
|
"PSetDisplay",
|
|
"pParams->Display"
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
return;
|
|
}
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETDISPLAY, // provider func index
|
|
&pfnTSPI_phoneSetDisplay, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetDisplay" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
pParams->lResult = CallSP6(
|
|
pfnTSPI_phoneSetDisplay,
|
|
"phoneSetDisplay",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwRow,
|
|
(DWORD) pParams->dwColumn,
|
|
(ULONG_PTR) (pParams->dwSize ?
|
|
pDataBuf + pParams->dwDisplayOffset : NULL),
|
|
(DWORD) pParams->dwSize
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetDisplay"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetGain(
|
|
PTCLIENT ptClient,
|
|
PPHONESETGAIN_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetGain;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETGAIN, // provider func index
|
|
&pfnTSPI_phoneSetGain, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetGain" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
|
|
(pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
|
|
{
|
|
lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetGain,
|
|
"phoneSetGain",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) (pParams->dwGain > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwGain)
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetGain"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetHookSwitch(
|
|
PTCLIENT ptClient,
|
|
PPHONESETHOOKSWITCH_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetHookSwitch;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETHOOKSWITCH, // provider func index
|
|
&pfnTSPI_phoneSetHookSwitch,// provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetHookSwitch" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
if (!(pParams->dwHookSwitchDevs & AllHookSwitchDevs) ||
|
|
(pParams->dwHookSwitchDevs & (~AllHookSwitchDevs)))
|
|
{
|
|
lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
|
|
}
|
|
else if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchMode) ||
|
|
(pParams->dwHookSwitchMode & ~AllHookSwitchModes))
|
|
{
|
|
lRequestID = PHONEERR_INVALHOOKSWITCHMODE;
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetHookSwitch,
|
|
"phoneSetHookSwitch",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDevs,
|
|
(DWORD) pParams->dwHookSwitchMode
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetHookSwitch"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetLamp(
|
|
PTCLIENT ptClient,
|
|
PPHONESETLAMP_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetLamp;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETLAMP, // provider func index
|
|
&pfnTSPI_phoneSetLamp, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetLamp" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
if (!IsOnlyOneBitSetInDWORD (pParams->dwLampMode) ||
|
|
(pParams->dwLampMode & ~AllLampModes))
|
|
{
|
|
lRequestID = PHONEERR_INVALLAMPMODE;
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetLamp,
|
|
"phoneSetLamp",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(DWORD) pParams->dwLampMode
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetLamp"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetRing(
|
|
PTCLIENT ptClient,
|
|
PPHONESETRING_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetRing;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETRING, // provider func index
|
|
&pfnTSPI_phoneSetRing, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetRing" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetRing,
|
|
"phoneSetRing",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwRingMode,
|
|
(DWORD) (pParams->dwVolume > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwVolume)
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetRing"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetStatusMessages(
|
|
PTCLIENT ptClient,
|
|
PPHONESETSTATUSMESSAGES_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex, bCloseMutex2;
|
|
HANDLE hMutex, hMutex2;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneSetStatusMessages;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETSTATUSMESSAGES, // provider func index
|
|
&pfnTSPI_phoneSetStatusMessages, // provider func pointer
|
|
NULL, // async request info
|
|
0, // client async request ID
|
|
"SetStatusMessages" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwAPIVersion, dwUnionPhoneStates, dwUnionButtonModes,
|
|
dwUnionButtonStates;
|
|
PTPHONECLIENT ptPhoneClient, ptPhoneClient2;
|
|
PTPHONE ptPhone;
|
|
|
|
|
|
//
|
|
// Safely get the ptPhone & api version
|
|
//
|
|
|
|
if (!(ptPhoneClient = ReferenceObject(
|
|
ghHandleTable,
|
|
pParams->hPhone,
|
|
0
|
|
)))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PSetStatusMessages_epilog;
|
|
}
|
|
|
|
try
|
|
{
|
|
ptPhone = ptPhoneClient->ptPhone;
|
|
|
|
dwAPIVersion = ptPhoneClient->dwAPIVersion;
|
|
|
|
if (ptPhoneClient->dwKey != TPHONECLIENT_KEY)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
|
|
|
|
//
|
|
// Validate the params
|
|
//
|
|
|
|
{
|
|
DWORD dwValidPhoneStates, dwValidButtonStates;
|
|
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwValidPhoneStates = AllPhoneStates1_0;
|
|
dwValidButtonStates = AllButtonStates1_0;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION1_4:
|
|
|
|
dwValidPhoneStates = AllPhoneStates1_4;
|
|
dwValidButtonStates = AllButtonStates1_4;
|
|
break;
|
|
|
|
}
|
|
|
|
if ((pParams->dwPhoneStates & ~dwValidPhoneStates))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONESTATE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
|
|
if ((pParams->dwButtonStates & ~dwValidButtonStates))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONSTATE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
|
|
if ((pParams->dwButtonModes & ~AllButtonModes))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONMODE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
|
|
if (pParams->dwButtonModes && !pParams->dwButtonStates)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONSTATE;
|
|
goto PSetStatusMessages_Dereference;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the REINIT bit is always set
|
|
//
|
|
|
|
pParams->dwPhoneStates |= PHONESTATE_REINIT;
|
|
|
|
|
|
//
|
|
// Get exclusive access to the device, determine the
|
|
// new union of all the client's status message settings
|
|
// and call down to the SP as appropriate
|
|
//
|
|
|
|
dwUnionPhoneStates = pParams->dwPhoneStates;
|
|
dwUnionButtonModes = pParams->dwButtonModes;
|
|
dwUnionButtonStates = pParams->dwButtonStates;
|
|
|
|
waitForExclAccess:
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
ptPhone,
|
|
&hMutex2,
|
|
&bCloseMutex2,
|
|
INFINITE
|
|
))
|
|
{
|
|
if (ptPhone->dwBusy)
|
|
{
|
|
MyReleaseMutex (hMutex2, bCloseMutex2);
|
|
Sleep (50);
|
|
goto waitForExclAccess;
|
|
}
|
|
|
|
for(
|
|
ptPhoneClient2 = ptPhone->ptPhoneClients;
|
|
ptPhoneClient2;
|
|
ptPhoneClient2 = ptPhoneClient2->pNextSametPhone
|
|
)
|
|
{
|
|
if (ptPhoneClient2 != ptPhoneClient)
|
|
{
|
|
dwUnionPhoneStates |= ptPhoneClient2->dwPhoneStates;
|
|
dwUnionButtonModes |= ptPhoneClient2->dwButtonModes;
|
|
dwUnionButtonStates |= ptPhoneClient2->dwButtonStates;
|
|
}
|
|
}
|
|
|
|
if ((dwUnionPhoneStates != ptPhone->dwUnionPhoneStates) ||
|
|
(dwUnionButtonModes != ptPhone->dwUnionButtonModes) ||
|
|
(dwUnionButtonStates != ptPhone->dwUnionButtonStates))
|
|
{
|
|
ptPhone->dwBusy = 1;
|
|
|
|
MyReleaseMutex (hMutex2, bCloseMutex2);
|
|
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetStatusMessages,
|
|
"phoneSetStatusMessages",
|
|
SP_FUNC_SYNC,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) dwUnionPhoneStates,
|
|
(DWORD) dwUnionButtonModes,
|
|
(DWORD) dwUnionButtonStates
|
|
);
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
ptPhone,
|
|
&hMutex2,
|
|
&bCloseMutex2,
|
|
INFINITE
|
|
))
|
|
{
|
|
ptPhone->dwBusy = 0;
|
|
|
|
if (pParams->lResult == 0)
|
|
{
|
|
ptPhone->dwUnionPhoneStates = dwUnionPhoneStates;
|
|
ptPhone->dwUnionButtonModes = dwUnionButtonModes;
|
|
ptPhone->dwUnionButtonStates = dwUnionButtonStates;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex2, bCloseMutex2);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MyReleaseMutex (hMutex2, bCloseMutex2);
|
|
}
|
|
|
|
if (pParams->lResult == 0)
|
|
{
|
|
if (WaitForExclusivePhoneClientAccess (ptPhoneClient))
|
|
{
|
|
ptPhoneClient->dwPhoneStates = pParams->dwPhoneStates;
|
|
ptPhoneClient->dwButtonModes = pParams->dwButtonModes;
|
|
ptPhoneClient->dwButtonStates = pParams->dwButtonStates;
|
|
|
|
UNLOCKTPHONECLIENT (ptPhoneClient);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The client is invalid now, but don't bother
|
|
// restoring the status msg states (will eventually
|
|
// get reset correctly & worse case is that SP just
|
|
// sends some extra msgs that get discarded)
|
|
//
|
|
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
PSetStatusMessages_Dereference:
|
|
|
|
DereferenceObject (ghHandleTable, pParams->hPhone, 1);
|
|
}
|
|
|
|
PSetStatusMessages_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"SetStatusMessages"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetVolume(
|
|
PTCLIENT ptClient,
|
|
PPHONESETVOLUME_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetVolume;
|
|
DWORD dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
&dwPrivilege, // req'd privileges (call only)
|
|
&hMutex, // mutex handle
|
|
&bCloseMutex, // close hMutex when finished
|
|
SP_PHONESETVOLUME, // provider func index
|
|
&pfnTSPI_phoneSetVolume, // provider func pointer
|
|
&pAsyncRequestInfo, // async request info
|
|
pParams->dwRemoteRequestID, // client async request ID
|
|
"SetVolume" // func name
|
|
|
|
)) > 0)
|
|
{
|
|
if (!IsOnlyOneBitSetInDWORD (pParams->dwHookSwitchDev) ||
|
|
(pParams->dwHookSwitchDev & ~AllHookSwitchDevs))
|
|
{
|
|
lRequestID = PHONEERR_INVALHOOKSWITCHDEV;
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetVolume,
|
|
"phoneSetVolume",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo->dwLocalRequestID,
|
|
(ULONG_PTR) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) (pParams->dwVolume > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwVolume)
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetVolume"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PShutdown(
|
|
PTCLIENT ptClient,
|
|
PPHONESHUTDOWN_PARAMS pParams,
|
|
DWORD dwParamsBufferSize,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
pParams->lResult = DestroytPhoneApp (pParams->hPhoneApp);
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
LOG((TL_TRACE,
|
|
"phoneShutdown: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#else
|
|
LOG((TL_TRACE,
|
|
"phoneShutdown: exit, result=x%x",
|
|
pParams->lResult
|
|
));
|
|
#endif
|
|
}
|