mirror of https://github.com/lianthony/NT4.0
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.
5013 lines
131 KiB
5013 lines
131 KiB
/*++ BUILD Version: 0000 // Increment this if a change has global effects
|
|
|
|
Copyright (c) 1995-1996 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 "..\client\client.h"
|
|
#include "server.h"
|
|
#include "phone.h"
|
|
|
|
|
|
extern TAPIGLOBALS TapiGlobals;
|
|
extern CRITICAL_SECTION gSafeMutexCritSec,
|
|
gRequestIDCritSec;
|
|
|
|
#if DBG
|
|
char *
|
|
PASCAL
|
|
MapResultCodeToText(
|
|
LONG lResult,
|
|
char *pszResult
|
|
);
|
|
#endif
|
|
|
|
void
|
|
DestroytPhoneClient(
|
|
PTPHONECLIENT ptPhoneClient
|
|
);
|
|
|
|
BOOL
|
|
IsAPIVersionInRange(
|
|
DWORD dwAPIVersion,
|
|
DWORD dwSPIVersion
|
|
);
|
|
|
|
BOOL
|
|
InitTapiStruct(
|
|
LPVOID pTapiStruct,
|
|
DWORD dwTotalSize,
|
|
DWORD dwFixedSize,
|
|
BOOL bZeroInit
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendMsgToPhoneClients(
|
|
PTPHONE ptPhone,
|
|
PTPHONECLIENT ptPhoneClienttoExclude,
|
|
DWORD dwMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2,
|
|
DWORD dwParam3
|
|
);
|
|
|
|
PTPHONE
|
|
PASCAL
|
|
WaitForExclusivetPhoneAccess(
|
|
HTAPIPHONE htPhone,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendReinitMsgToAllXxxApps(
|
|
void
|
|
);
|
|
|
|
PTCLIENT
|
|
PASCAL
|
|
WaitForExclusiveClientAccess(
|
|
PTCLIENT ptClient,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
);
|
|
|
|
void
|
|
CALLBACK
|
|
CompletionProcSP(
|
|
DWORD dwRequestID,
|
|
LONG lResult
|
|
);
|
|
|
|
void
|
|
PASCAL
|
|
SendAMsgToAllPhoneApps(
|
|
DWORD dwWantVersion,
|
|
DWORD dwMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2,
|
|
DWORD dwParam3
|
|
);
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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],
|
|
"lineNegotiateExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) dwDeviceID,
|
|
(DWORD) pLookupEntry->dwSPIVersion,
|
|
(DWORD) dwExtVersion,
|
|
(DWORD) dwExtVersion,
|
|
(DWORD) &dwNegotiatedExtVersion
|
|
);
|
|
|
|
bResult = ((lResult || !dwNegotiatedExtVersion) ? FALSE : TRUE);
|
|
}
|
|
else
|
|
{
|
|
bResult = FALSE;
|
|
}
|
|
|
|
IsValidPhoneExtVersion_return:
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
PTPHONEAPP
|
|
PASCAL
|
|
IsValidPhoneApp(
|
|
HPHONEAPP hPhoneApp,
|
|
PTCLIENT ptClient
|
|
)
|
|
{
|
|
try
|
|
{
|
|
if (IsBadPtrKey (hPhoneApp, TPHONEAPP_KEY) ||
|
|
(*( ((LPDWORD) hPhoneApp) + 1) != (DWORD) ptClient))
|
|
{
|
|
hPhoneApp = (HPHONEAPP) 0;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
hPhoneApp = (HPHONEAPP) 0;
|
|
}
|
|
|
|
return ((PTPHONEAPP) hPhoneApp);
|
|
}
|
|
|
|
|
|
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.
|
|
//
|
|
|
|
#if DBG
|
|
char szFunc[] = "ValidateButtonInfo";
|
|
#endif
|
|
DWORD dwTotalSize = pButtonInfoApp->dwTotalSize, dwFixedSizeApp,
|
|
dwFixedSizeSP;
|
|
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwFixedSizeApp = 36; // 9 * sizeof (DWORD)
|
|
break;
|
|
|
|
case TAPI_VERSION1_4:
|
|
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_VERSION_CURRENT:
|
|
|
|
dwFixedSizeSP = sizeof (PHONEBUTTONINFO);
|
|
break;
|
|
|
|
default:
|
|
|
|
return PHONEERR_INVALPHONEHANDLE;
|
|
}
|
|
|
|
if (dwTotalSize < dwFixedSizeApp)
|
|
{
|
|
DBGOUT((
|
|
3,
|
|
"%sbad dwTotalSize, x%x (minimum valid size=x%x)",
|
|
szFunc,
|
|
dwTotalSize,
|
|
dwFixedSizeApp
|
|
));
|
|
|
|
return PHONEERR_STRUCTURETOOSMALL;
|
|
}
|
|
|
|
// BUGBUG ValidateButtonInfo: validate dwButtonMode, dwButtonFunction fields
|
|
|
|
if (ISBADSIZEOFFSET(
|
|
dwTotalSize,
|
|
dwFixedSizeApp,
|
|
pButtonInfoApp->dwButtonTextSize,
|
|
pButtonInfoApp->dwButtonTextOffset,
|
|
szFunc,
|
|
"ButtonText"
|
|
) ||
|
|
|
|
ISBADSIZEOFFSET(
|
|
dwTotalSize,
|
|
dwFixedSizeApp,
|
|
pButtonInfoApp->dwDevSpecificSize,
|
|
pButtonInfoApp->dwDevSpecificOffset,
|
|
szFunc,
|
|
"DevSpecific"
|
|
))
|
|
{
|
|
return PHONEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
if (dwAPIVersion < TAPI_VERSION1_4)
|
|
{
|
|
goto ValidateButtonInfo_checkFixedSizes;
|
|
}
|
|
|
|
// BUGBUG ValidateButtonInfo: validate dwButtonState field
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
void
|
|
DestroytPhone(
|
|
PTPHONE ptPhone,
|
|
BOOL bUnconditional
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
DBGOUT((3, "DestroytPhone: enter, ptPhone=x%x", ptPhone));
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
(HTAPIPHONE) 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.
|
|
//
|
|
|
|
{
|
|
BOOL bExit;
|
|
|
|
|
|
if (ptPhone->dwKey == TPHONE_KEY &&
|
|
(bUnconditional == TRUE || ptPhone->ptPhoneClients == NULL))
|
|
{
|
|
SendMsgToPhoneClients (ptPhone, NULL, PHONE_CLOSE, 0, 0, 0);
|
|
ptPhone->dwKey = INVAL_KEY;
|
|
bExit = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bExit = TRUE;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
if (bExit)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
hMutex = ptPhone->hMutex;
|
|
|
|
destroy_tPhoneClients:
|
|
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
ptPhoneClient = ptPhone->ptPhoneClients;
|
|
|
|
ReleaseMutex (hMutex);
|
|
|
|
if (ptPhoneClient)
|
|
{
|
|
DestroytPhoneClient (ptPhoneClient);
|
|
goto destroy_tPhoneClients;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Tell the provider to close the widget
|
|
//
|
|
|
|
{
|
|
PTPROVIDER ptProvider = ptPhone->ptProvider;
|
|
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
WaitForSingleObject (ptProvider->hMutex, INFINITE);
|
|
}
|
|
|
|
CallSP1(
|
|
ptProvider->apfn[SP_PHONECLOSE],
|
|
"phoneClose",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) 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);
|
|
|
|
// BUGBUG DestroytPhone: wrap in mutex (pEntry->ptPhone = NULL)
|
|
|
|
pEntry->ptPhone = NULL;
|
|
}
|
|
|
|
ServerFree (ptPhone);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DestroytPhoneClient(
|
|
PTPHONECLIENT ptPhoneClient
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
DBGOUT((3, "DestroytPhoneClient: enter, ptPhoneClient=x%x",ptPhoneClient));
|
|
|
|
if (WaitForMutex(
|
|
ptPhoneClient->hMutex,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
ptPhoneClient,
|
|
TPHONECLIENT_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
PTPHONE ptPhone;
|
|
|
|
|
|
//
|
|
// If the key is bad another thread is in the process of
|
|
// destroying this widget, so just release the mutex &
|
|
// return. Otherwise, mark the widget as bad, release
|
|
// the mutex, and continue on.
|
|
//
|
|
|
|
{
|
|
BOOL bExit;
|
|
|
|
|
|
if (ptPhoneClient->dwKey == TPHONECLIENT_KEY)
|
|
{
|
|
ptPhoneClient->dwKey = INVAL_KEY;
|
|
|
|
bExit = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bExit = TRUE;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
if (bExit)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Remove tPhoneClient from tPhoneApp'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.
|
|
//
|
|
|
|
{
|
|
PTPHONEAPP ptPhoneApp = (PTPHONEAPP) ptPhoneClient->ptPhoneApp;
|
|
|
|
|
|
WaitForSingleObject (ptPhoneApp->hMutex, INFINITE);
|
|
|
|
if (ptPhoneClient->pNextSametPhoneApp)
|
|
{
|
|
ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
|
|
ptPhoneClient->pPrevSametPhoneApp;
|
|
}
|
|
|
|
if (ptPhoneClient->pPrevSametPhoneApp)
|
|
{
|
|
ptPhoneClient->pPrevSametPhoneApp->pNextSametPhoneApp =
|
|
ptPhoneClient->pNextSametPhoneApp;
|
|
}
|
|
else
|
|
{
|
|
ptPhoneApp->ptPhoneClients = ptPhoneClient->pNextSametPhoneApp;
|
|
}
|
|
|
|
ReleaseMutex (ptPhoneApp->hMutex);
|
|
}
|
|
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
CallSP2(
|
|
ptPhone->ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) 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)
|
|
{
|
|
SendMsgToPhoneClients(
|
|
ptPhone,
|
|
NULL,
|
|
PHONE_STATE,
|
|
(ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
PHONESTATE_OWNER : PHONESTATE_MONITORS),
|
|
(ptPhoneClient->dwPrivilege == PHONEPRIVILEGE_OWNER ?
|
|
0 : ptPhone->dwNumMonitors),
|
|
0
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This was the last client so destroy the tPhone too
|
|
//
|
|
|
|
ReleaseMutex (hMutex);
|
|
hMutex = NULL;
|
|
DestroytPhone (ptPhone, FALSE); // conditional destroy
|
|
}
|
|
}
|
|
|
|
if (hMutex)
|
|
{
|
|
ReleaseMutex (hMutex);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
WaitForMutex(
|
|
ptPhoneClient->hMutex,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
NULL,
|
|
0,
|
|
INFINITE
|
|
);
|
|
|
|
if (bCloseMutex)
|
|
{
|
|
CloseHandle (ptPhoneClient->hMutex);
|
|
ReleaseMutex (hMutex);
|
|
CloseHandle (hMutex);
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection (&gSafeMutexCritSec);
|
|
|
|
ReleaseMutex (hMutex);
|
|
CloseHandle (hMutex);
|
|
|
|
LeaveCriticalSection (&gSafeMutexCritSec);
|
|
}
|
|
|
|
ServerFree (ptPhoneClient);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DestroytPhoneApp(
|
|
PTPHONEAPP ptPhoneApp
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
DBGOUT((3, "DestroytPhoneApp: enter, ptPhoneApp=x%x", ptPhoneApp));
|
|
|
|
if (WaitForMutex(
|
|
ptPhoneApp->hMutex,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
ptPhoneApp,
|
|
TPHONEAPP_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
//
|
|
// If the key is bad another thread is in the process of
|
|
// destroying this widget, so just release the mutex &
|
|
// return. Otherwise, mark the widget as bad, release
|
|
// the mutex, and continue on.
|
|
//
|
|
|
|
|
|
{
|
|
BOOL bExit;
|
|
|
|
|
|
if (ptPhoneApp->dwKey == TPHONEAPP_KEY)
|
|
{
|
|
ptPhoneApp->dwKey = INVAL_KEY;
|
|
|
|
bExit = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bExit = TRUE;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
if (bExit)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Destroy all the tPhoneClients. 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
|
|
// tPhoneClient's, since another thread might be destroying a
|
|
// tPhoneClient too.
|
|
//
|
|
|
|
{
|
|
PTPHONECLIENT ptPhoneClient;
|
|
|
|
|
|
hMutex = ptPhoneApp->hMutex;
|
|
|
|
destroy_tPhoneClients:
|
|
|
|
WaitForSingleObject (hMutex, INFINITE);
|
|
|
|
ptPhoneClient = ptPhoneApp->ptPhoneClients;
|
|
|
|
ReleaseMutex (hMutex);
|
|
|
|
if (ptPhoneClient)
|
|
{
|
|
DestroytPhoneClient (ptPhoneClient);
|
|
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;
|
|
|
|
|
|
WaitForSingleObject (ptClient->hMutex, INFINITE);
|
|
|
|
if (ptPhoneApp->pNext)
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
|
|
}
|
|
|
|
if (ptPhoneApp->pPrev)
|
|
{
|
|
ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
|
|
}
|
|
else
|
|
{
|
|
ptClient->ptPhoneApps = ptPhoneApp->pNext;
|
|
}
|
|
|
|
ReleaseMutex (ptClient->hMutex);
|
|
}
|
|
|
|
|
|
//
|
|
// Decrement total num inits & see if we need to go thru shutdown
|
|
//
|
|
|
|
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
|
|
|
|
//assert(TapiGlobals.dwNumLineInits != 0);
|
|
|
|
TapiGlobals.dwNumPhoneInits--;
|
|
|
|
if ((TapiGlobals.dwNumLineInits == 0) &&
|
|
(TapiGlobals.dwNumPhoneInits == 0))
|
|
{
|
|
ServerShutdown();
|
|
}
|
|
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
|
|
|
|
//
|
|
// Free the resources
|
|
//
|
|
|
|
CloseHandle (ptPhoneApp->hMutex);
|
|
|
|
ServerFree (ptPhoneApp);
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
PhoneProlog(
|
|
PTCLIENT ptClient,
|
|
DWORD dwArgType,
|
|
DWORD dwArg,
|
|
LPVOID phdXxx,
|
|
DWORD dwPrivilege,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTSPIFuncIndex,
|
|
FARPROC *ppfnTSPI_phoneXxx,
|
|
PASYNCREQUESTINFO *ppAsyncRequestInfo,
|
|
DWORD dwRemoteRequestID
|
|
#if DBG
|
|
,char *pszFuncName
|
|
#endif
|
|
)
|
|
{
|
|
LONG lResult = 0;
|
|
PTPROVIDER ptProvider;
|
|
|
|
|
|
DBGOUT((3, "PhoneProlog: (phone%s) enter", pszFuncName));
|
|
|
|
*phMutex = NULL;
|
|
*pbDupedMutex = FALSE;
|
|
|
|
if (ppAsyncRequestInfo)
|
|
{
|
|
*ppAsyncRequestInfo = (PASYNCREQUESTINFO) NULL;
|
|
}
|
|
|
|
if (TapiGlobals.dwNumPhoneInits == 0)
|
|
{
|
|
lResult = PHONEERR_UNINITIALIZED;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
switch (dwArgType)
|
|
{
|
|
case ANY_RT_HPHONE:
|
|
{
|
|
try
|
|
{
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) dwArg;
|
|
|
|
|
|
if (IsBadPtrKey (ptPhoneClient, TPHONECLIENT_KEY) ||
|
|
(ptPhoneClient->ptClient != ptClient))
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
ptProvider = ptPhoneClient->ptPhone->ptProvider;
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
if (!WaitForMutex(
|
|
ptProvider->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
ptProvider,
|
|
TPROVIDER_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
goto PhoneProlog_return;
|
|
}
|
|
}
|
|
|
|
*((HDRVPHONE *) phdXxx) = ptPhoneClient->ptPhone->hdPhone;
|
|
|
|
if (ptPhoneClient->dwPrivilege < dwPrivilege)
|
|
{
|
|
lResult = PHONEERR_NOTOWNER;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
if ((ptPhoneClient->dwKey != TPHONECLIENT_KEY) ||
|
|
(ptPhoneClient->ptClient != ptClient))
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
}
|
|
myexcept
|
|
{
|
|
lResult = PHONEERR_INVALPHONEHANDLE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case DEVICE_ID:
|
|
{
|
|
PTPHONELOOKUPENTRY pPhoneLookupEntry;
|
|
|
|
|
|
if (dwArg && !IsValidPhoneApp ((HPHONEAPP) dwArg, ptClient))
|
|
{
|
|
lResult = PHONEERR_INVALAPPHANDLE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
if (!(pPhoneLookupEntry = GetPhoneLookupEntry (dwPrivilege)))
|
|
{
|
|
lResult = PHONEERR_BADDEVICEID;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
if (pPhoneLookupEntry->bRemoved)
|
|
{
|
|
lResult = PHONEERR_NODEVICE;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
if (!(ptProvider = pPhoneLookupEntry->ptProvider))
|
|
{
|
|
lResult = PHONEERR_NODRIVER;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
// BUGBUG wrap in try/except
|
|
|
|
if (ptProvider->dwTSPIOptions & LINETSPIOPTION_NONREENTRANT)
|
|
{
|
|
if (!WaitForMutex(
|
|
ptProvider->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
ptProvider,
|
|
TPROVIDER_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
lResult = PHONEERR_OPERATIONFAILED;
|
|
goto PhoneProlog_return;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) dwArg;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
|
|
|
|
if (!(pAsyncRequestInfo = ServerAlloc (sizeof(ASYNCREQUESTINFO))))
|
|
{
|
|
lResult = PHONEERR_NOMEM;
|
|
goto PhoneProlog_return;
|
|
}
|
|
|
|
pAsyncRequestInfo->dwKey = TASYNC_KEY;
|
|
pAsyncRequestInfo->ptClient = ptClient;
|
|
pAsyncRequestInfo->pInitData =
|
|
(DWORD) ((PTPHONEAPP) ptPhoneClient->ptPhoneApp)->lpfnCallback;
|
|
pAsyncRequestInfo->dwCallbackInst = ptPhoneClient->dwCallbackInstance;
|
|
pAsyncRequestInfo->bLineFunc = FALSE;
|
|
|
|
if (dwRemoteRequestID)
|
|
{
|
|
lResult = pAsyncRequestInfo->dwRequestID = dwRemoteRequestID;
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection (&gRequestIDCritSec);
|
|
|
|
lResult =
|
|
pAsyncRequestInfo->dwRequestID = TapiGlobals.dwAsyncRequestID;
|
|
|
|
if (++TapiGlobals.dwAsyncRequestID & 0x80000000)
|
|
{
|
|
TapiGlobals.dwAsyncRequestID = 1;
|
|
}
|
|
|
|
LeaveCriticalSection (&gRequestIDCritSec);
|
|
}
|
|
|
|
*ppAsyncRequestInfo = pAsyncRequestInfo;
|
|
}
|
|
|
|
PhoneProlog_return:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"PhoneProlog: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (lResult, szResult)
|
|
));
|
|
}
|
|
#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];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"PhoneEpilogSync: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (*plResult, szResult)
|
|
));
|
|
}
|
|
#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 != (LONG) pAsyncRequestInfo)
|
|
{
|
|
//
|
|
// 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 ((DWORD) pAsyncRequestInfo, *plResult);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// 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)
|
|
//
|
|
|
|
ServerFree (pAsyncRequestInfo);
|
|
}
|
|
|
|
*plResult = lRequestID;
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"PhoneEpilogSync: (phone%s) exit, result=%s",
|
|
pszFuncName,
|
|
MapResultCodeToText (lRequestID, szResult)
|
|
));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
PTPHONE
|
|
PASCAL
|
|
WaitForExclusivetPhoneAccess(
|
|
HTAPIPHONE htPhone,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
)
|
|
{
|
|
try
|
|
{
|
|
if (!IsBadPtrKey (htPhone, TPHONE_KEY) &&
|
|
|
|
WaitForMutex(
|
|
((PTPHONE) htPhone)->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
(LPVOID) htPhone,
|
|
TPHONE_KEY,
|
|
INFINITE
|
|
))
|
|
{
|
|
if (((PTPHONE) htPhone)->dwKey == TPHONE_KEY)
|
|
{
|
|
return ((PTPHONE) htPhone);
|
|
}
|
|
|
|
MyReleaseMutex (*phMutex, *pbDupedMutex);
|
|
}
|
|
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PTPHONEAPP
|
|
PASCAL
|
|
WaitForExclusivePhoneAppAccess(
|
|
HPHONEAPP hPhoneApp,
|
|
PTCLIENT ptClient,
|
|
HANDLE *phMutex,
|
|
BOOL *pbDupedMutex,
|
|
DWORD dwTimeout
|
|
)
|
|
{
|
|
try
|
|
{
|
|
if (IsBadPtrKey (hPhoneApp, TPHONEAPP_KEY))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (WaitForMutex(
|
|
((PTPHONEAPP) hPhoneApp)->hMutex,
|
|
phMutex,
|
|
pbDupedMutex,
|
|
(LPVOID) hPhoneApp,
|
|
TPHONEAPP_KEY,
|
|
dwTimeout
|
|
))
|
|
{
|
|
if (((PTPHONEAPP) hPhoneApp)->dwKey == TPHONEAPP_KEY &&
|
|
((PTPHONEAPP) hPhoneApp)->ptClient == ptClient)
|
|
{
|
|
return ((PTPHONEAPP) hPhoneApp);
|
|
}
|
|
|
|
MyReleaseMutex (*phMutex, *pbDupedMutex);
|
|
}
|
|
|
|
}
|
|
myexcept
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneAppListFromClient(
|
|
PTCLIENT ptClient,
|
|
PTPOINTERLIST *ppList
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
if (WaitForExclusiveClientAccess(
|
|
ptClient,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
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)
|
|
)))
|
|
{
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
CopyMemory(
|
|
pNewList->aEntries,
|
|
pList->aEntries,
|
|
dwNumUsedEntries * sizeof (LPVOID)
|
|
);
|
|
|
|
if (pList != *ppList)
|
|
{
|
|
ServerFree (pList);
|
|
}
|
|
|
|
pList = pNewList;
|
|
}
|
|
|
|
pList->aEntries[dwNumUsedEntries++] = ptPhoneApp;
|
|
|
|
ptPhoneApp = ptPhoneApp->pNext;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
|
|
pList->dwNumUsedEntries = dwNumUsedEntries;
|
|
|
|
*ppList = pList;
|
|
}
|
|
else
|
|
{
|
|
return PHONEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LONG
|
|
PASCAL
|
|
GetPhoneClientListFromPhone(
|
|
PTPHONE ptPhone,
|
|
PTPOINTERLIST *ppList
|
|
)
|
|
{
|
|
BOOL bDupedMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
if (WaitForExclusivetPhoneAccess(
|
|
(HTAPIPHONE) 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 LINEERR_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 dwMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2,
|
|
DWORD dwParam3
|
|
)
|
|
{
|
|
DWORD i;
|
|
TPOINTERLIST clientList, *pClientList = &clientList;
|
|
ASYNCEVENTMSG msg;
|
|
|
|
|
|
if (dwMsg == PHONE_STATE && dwParam1 & PHONESTATE_REINIT)
|
|
{
|
|
SendReinitMsgToAllXxxApps();
|
|
|
|
if (dwParam1 == PHONESTATE_REINIT)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
dwParam1 &= ~PHONESTATE_REINIT;
|
|
}
|
|
}
|
|
|
|
if (GetPhoneClientListFromPhone (ptPhone, &pClientList) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
msg.dwTotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.pfnPostProcessProc = 0;
|
|
msg.dwMsg = dwMsg;
|
|
msg.dwParam1 = dwParam1;
|
|
msg.dwParam2 = dwParam2;
|
|
msg.dwParam3 = dwParam3;
|
|
|
|
for (i = 0; i < pClientList->dwNumUsedEntries; i++)
|
|
{
|
|
try
|
|
{
|
|
PTCLIENT ptClient;
|
|
PTPHONECLIENT ptPhoneClient = pClientList->aEntries[i];
|
|
|
|
|
|
if (ptPhoneClient == ptPhoneClientToExclude)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (dwMsg == PHONE_STATE)
|
|
{
|
|
DWORD dwPhoneStates = dwParam1;
|
|
|
|
|
|
//
|
|
// Munge the state flags so we don't pass
|
|
// unexpected flags to old apps
|
|
//
|
|
|
|
switch (ptPhoneClient->dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwPhoneStates &= AllPhoneStates1_0;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION1_4:
|
|
// case TAPI_VERSION_CURRENT:
|
|
|
|
dwPhoneStates &= AllPhoneStates1_4;
|
|
break;
|
|
}
|
|
|
|
if (dwParam1 & PHONESTATE_CAPSCHANGE)
|
|
{
|
|
// BUGBUG send REINIT to 1_0 apps (dwParam3 = dwParam1)
|
|
}
|
|
|
|
if (ptPhoneClient->dwPhoneStates & dwPhoneStates)
|
|
{
|
|
msg.dwParam1 = dwPhoneStates;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (dwMsg == PHONE_BUTTON)
|
|
{
|
|
DWORD dwButtonModes = dwParam2,
|
|
dwButtonStates = dwParam3;
|
|
|
|
|
|
//
|
|
// Munge the state flags so we don't pass
|
|
// unexpected flags to old apps
|
|
//
|
|
|
|
switch (ptPhoneClient->dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
|
|
dwButtonStates &= AllButtonStates1_0;
|
|
break;
|
|
|
|
default: // case TAPI_VERSION1_4:
|
|
// case TAPI_VERSION_CURRENT:
|
|
|
|
dwButtonStates &= AllButtonStates1_4;
|
|
break;
|
|
}
|
|
|
|
dwButtonStates &= ptPhoneClient->dwButtonStates;
|
|
|
|
if ((dwButtonModes &= ptPhoneClient->dwButtonModes) ||
|
|
dwButtonStates)
|
|
{
|
|
msg.dwParam2 = dwButtonModes;
|
|
msg.dwParam3 = dwButtonStates;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
msg.pInitData = (DWORD)
|
|
((PTPHONEAPP) ptPhoneClient->ptPhoneApp)->lpfnCallback;
|
|
msg.hDevice = (DWORD) ptPhoneClient->hRemotePhone;
|
|
msg.dwCallbackInst = ptPhoneClient->dwCallbackInstance;
|
|
|
|
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,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2,
|
|
DWORD dwParam3
|
|
)
|
|
{
|
|
switch (dwMsg)
|
|
{
|
|
case PHONE_CLOSE:
|
|
|
|
DestroytPhone ((PTPHONE) htPhone, TRUE); // unconditional destroy
|
|
break;
|
|
|
|
case PHONE_DEVSPECIFIC:
|
|
case PHONE_STATE:
|
|
case PHONE_BUTTON:
|
|
|
|
SendMsgToPhoneClients(
|
|
(PTPHONE) htPhone,
|
|
NULL,
|
|
dwMsg,
|
|
dwParam1,
|
|
dwParam2,
|
|
dwParam3
|
|
);
|
|
|
|
break;
|
|
|
|
case PHONE_CREATE:
|
|
{
|
|
LONG lResult;
|
|
DWORD dwDeviceID;
|
|
TSPIPROC pfnTSPI_providerCreatePhoneDevice;
|
|
PTPROVIDER ptProvider = (PTPROVIDER) dwParam1;
|
|
PTPHONELOOKUPTABLE pTable, pPrevTable;
|
|
PTPHONELOOKUPENTRY pEntry;
|
|
|
|
|
|
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)
|
|
//
|
|
|
|
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
|
|
|
|
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)
|
|
)))
|
|
{
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
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) dwParam1;
|
|
|
|
|
|
//
|
|
// 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,
|
|
dwParam2,
|
|
dwDeviceID
|
|
|
|
)) == 0)
|
|
{
|
|
TSPIPROC pfnTSPI_phoneNegotiateTSPIVersion =
|
|
ptProvider->apfn[SP_PHONENEGOTIATETSPIVERSION];
|
|
|
|
|
|
if ((lResult = CallSP4(
|
|
pfnTSPI_phoneNegotiateTSPIVersion,
|
|
"",
|
|
SP_FUNC_SYNC,
|
|
dwDeviceID,
|
|
TAPI_VERSION1_0,
|
|
TAPI_VERSION_CURRENT,
|
|
(DWORD) &pEntry->dwSPIVersion
|
|
|
|
)) == 0)
|
|
{
|
|
PTCLIENT ptClient = TapiGlobals.ptClients;
|
|
ASYNCEVENTMSG msg;
|
|
|
|
|
|
pTable->dwNumUsedEntries++;
|
|
|
|
TapiGlobals.dwNumPhones++;
|
|
|
|
msg.dwTotalSize = sizeof (ASYNCEVENTMSG);
|
|
msg.pfnPostProcessProc =
|
|
msg.hDevice =
|
|
msg.dwCallbackInst =
|
|
msg.dwParam2 =
|
|
msg.dwParam3 = 0;
|
|
|
|
while (ptClient)
|
|
{
|
|
// BUGBUG WaitForSingleObject (ptClient->hMutex,
|
|
|
|
PTPHONEAPP ptPhoneApp = ptClient->ptPhoneApps;
|
|
|
|
|
|
while (ptPhoneApp)
|
|
{
|
|
if (ptPhoneApp->dwAPIVersion == TAPI_VERSION1_0)
|
|
{
|
|
msg.dwMsg = PHONE_STATE;
|
|
msg.dwParam1 = PHONESTATE_REINIT;
|
|
}
|
|
else
|
|
{
|
|
msg.dwMsg = PHONE_CREATE;
|
|
msg.dwParam1 = dwDeviceID;
|
|
}
|
|
|
|
msg.pInitData = (DWORD) ptPhoneApp->lpfnCallback;
|
|
|
|
WriteEventBuffer (ptClient, &msg);
|
|
|
|
ptPhoneApp = ptPhoneApp->pNext;
|
|
}
|
|
|
|
ptClient = ptClient->pNext;
|
|
}
|
|
|
|
// break;
|
|
}
|
|
}
|
|
|
|
if (lResult)
|
|
{
|
|
CloseHandle (pEntry->hMutex);
|
|
}
|
|
}
|
|
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
break;
|
|
}
|
|
case PHONE_REMOVE:
|
|
{
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
|
|
|
|
if (!(pLookupEntry = GetPhoneLookupEntry (dwParam1)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Mark the lookup table entry as removed
|
|
//
|
|
|
|
pLookupEntry->bRemoved = 1;
|
|
|
|
DestroytPhone (pLookupEntry->ptPhone, TRUE); // unconditional destroy
|
|
|
|
SendAMsgToAllPhoneApps (TAPI_VERSION2_0, PHONE_REMOVE, dwParam1, 0, 0);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
DBGOUT((3, "PhoneEventProc: unknown msg, dwMsg=%ld", dwMsg));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CALLBACK
|
|
PhoneEventProcSP(
|
|
HTAPIPHONE htPhone,
|
|
DWORD dwMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2,
|
|
DWORD dwParam3
|
|
)
|
|
{
|
|
PSPEVENT pSPEvent;
|
|
|
|
DBGOUT((
|
|
3,
|
|
"PhoneEventProc: enter\n\thtPhone=x%lx, Msg=x%lx\n" \
|
|
"\tP1=x%lx, P2=x%lx, P3=x%lx",
|
|
htPhone,
|
|
dwMsg,
|
|
dwParam1,
|
|
dwParam2,
|
|
dwParam3
|
|
));
|
|
|
|
if ((pSPEvent = (PSPEVENT) ServerAlloc (sizeof (SPEVENT))))
|
|
{
|
|
pSPEvent->dwType = SP_PHONE_EVENT;
|
|
pSPEvent->htPhone = htPhone;
|
|
pSPEvent->dwMsg = dwMsg;
|
|
pSPEvent->dwParam1 = dwParam1;
|
|
pSPEvent->dwParam2 = dwParam2;
|
|
pSPEvent->dwParam3 = dwParam3;
|
|
|
|
QueueSPEvent (pSPEvent);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Alloc failed, so call the event proc within the SP's context
|
|
//
|
|
|
|
PhoneEventProc (htPhone, dwMsg, dwParam1, dwParam2, dwParam3);
|
|
}
|
|
}
|
|
|
|
void
|
|
WINAPI
|
|
PClose(
|
|
PPHONECLOSE_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneClose;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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)
|
|
{
|
|
DestroytPhoneClient ((PTPHONECLIENT) 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->dwParam2 == 0) // success
|
|
{
|
|
//
|
|
// Make sure to keep the total size 64-bit aligned
|
|
//
|
|
|
|
pNewAsyncEventMsg->dwTotalSize +=
|
|
(pAsyncRequestInfo->dwParam2 + 7) & 0xfffffff8;
|
|
|
|
pNewAsyncEventMsg->dwParam3 = pAsyncRequestInfo->dwParam1; // lpParams
|
|
pNewAsyncEventMsg->dwParam4 = pAsyncRequestInfo->dwParam2; // dwSize
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PDevSpecific(
|
|
PPHONEDEVSPECIFIC_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneDevSpecific;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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 = (LPBYTE) ServerAlloc (pParams->dwParamsSize);
|
|
|
|
|
|
//
|
|
// 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 = (DWORD) pParams->lpParams;
|
|
pAsyncRequestInfo->dwParam2 = pParams->dwParamsSize;
|
|
pAsyncRequestInfo->dwParam3 = (DWORD) pBuf;
|
|
|
|
pAsyncRequestInfo->pfnClientPostProcessProc =
|
|
pParams->pfnPostProcessProc;
|
|
|
|
pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneDevSpecific,
|
|
"phoneDevSpecific",
|
|
SP_FUNC_ASYNC,
|
|
(DWORD) pAsyncRequestInfo,
|
|
(DWORD) hdPhone,
|
|
(DWORD) (pParams->dwParamsSize ?
|
|
pBuf + sizeof (ASYNCEVENTMSG) : NULL),
|
|
(DWORD) pParams->dwParamsSize
|
|
);
|
|
}
|
|
|
|
PDevSpecific_epilog:
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"DevSpecific"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetButtonInfo(
|
|
PPHONEGETBUTTONINFO_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetButtonInfo;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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;
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure for the specified API
|
|
// version, verify client's buffer is big enough
|
|
//
|
|
|
|
dwAPIVersion = ((PTPHONECLIENT) pParams->hPhone)->dwAPIVersion;
|
|
|
|
dwTotalSize = pParams->u.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
|
|
//
|
|
|
|
dwSPIVersion = ((PTPHONECLIENT)
|
|
pParams->hPhone)->ptPhone->dwSPIVersion;
|
|
|
|
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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(DWORD) 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->u.dwButtonInfoTotalSize;
|
|
pButtonInfo->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->u.dwButtonInfoOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) +
|
|
pButtonInfo->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetButtonInfo_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetButtonInfo"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetData(
|
|
PPHONEGETDATA_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetData;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwDataID,
|
|
(DWORD) 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(
|
|
PPHONEGETDEVCAPS_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneGetDevCaps;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->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->u.dwPhoneCapsTotalSize;
|
|
|
|
switch (dwAPIVersion)
|
|
{
|
|
case TAPI_VERSION1_0:
|
|
case TAPI_VERSION1_4:
|
|
|
|
dwFixedSizeClient = 144; // 36 * sizeof (DWORD)
|
|
break;
|
|
|
|
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;
|
|
|
|
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) dwAPIVersion,
|
|
(DWORD) pParams->dwExtVersion,
|
|
(DWORD) 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->u.dwPhoneCapsTotalSize;
|
|
pCaps->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->u.dwPhoneCapsOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pCaps->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetDevCaps_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetDevCaps"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetDisplay(
|
|
PPHONEGETDISPLAY_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetDisplay;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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->u.dwDisplayTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetDisplay_epilog;
|
|
}
|
|
|
|
if ((pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneGetDisplay,
|
|
"phoneGetDisplay",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pDisplay
|
|
|
|
)) == 0)
|
|
{
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
//
|
|
// Indicate how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->u.dwDisplayOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pDisplay->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetDisplay_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetDisplay"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetGain(
|
|
PPHONEGETGAIN_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetGain;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) &pParams->dwGain
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETGAIN_PARAMS);
|
|
}
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetGain"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetHookSwitch(
|
|
PPHONEGETHOOKSWITCH_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetHookSwitch;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) &pParams->dwHookSwitchDevs
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETHOOKSWITCH_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetHookSwitch"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetIcon(
|
|
PPHONEGETICON_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
WCHAR *pszDeviceClass;
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneGetIcon;
|
|
|
|
|
|
pszDeviceClass = (WCHAR *) (pParams->dwDeviceClassOffset == TAPI_NO_DATA ?
|
|
NULL : pDataBuf + pParams->dwDeviceClassOffset);
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
DEVICE_ID, // widget type
|
|
0, // client widget handle
|
|
NULL, // provider widget handle
|
|
(DWORD) 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,
|
|
pParams->dwDeviceID,
|
|
(DWORD) pszDeviceClass,
|
|
(DWORD) &pParams->hIcon
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETICON_PARAMS);
|
|
}
|
|
}
|
|
else if (pParams->lResult == PHONEERR_OPERATIONUNAVAIL)
|
|
{
|
|
if ((pszDeviceClass == NULL) ||
|
|
(lstrcmpW(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
|
|
PGetID(
|
|
PPHONEGETID_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetID;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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 (lstrcmpiW(
|
|
(PWSTR)(pDataBuf + pParams->dwDeviceClassOffset),
|
|
L"tapi/phone"
|
|
|
|
) == 0)
|
|
{
|
|
if (!InitTapiStruct(
|
|
pID,
|
|
pParams->u.dwDeviceIDTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
pID->dwNeededSize += sizeof (DWORD);
|
|
|
|
if (pID->dwTotalSize >= pID->dwNeededSize)
|
|
{
|
|
try
|
|
{
|
|
*((LPDWORD)(pID + 1)) = ((PTPHONECLIENT) pParams->hPhone)
|
|
->ptPhone->dwDeviceID;
|
|
}
|
|
myexcept
|
|
{
|
|
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->u.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
|
|
//
|
|
|
|
if (!(pszDeviceClass = (WCHAR *) ServerAlloc( sizeof(WCHAR) * (1 +
|
|
lstrlenW ((PWSTR)(pDataBuf + pParams->dwDeviceClassOffset)))
|
|
)))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
lstrcpyW(pszDeviceClass, (PWSTR)(pDataBuf + pParams->dwDeviceClassOffset));
|
|
|
|
|
|
if (!InitTapiStruct(
|
|
pID,
|
|
pParams->u.dwDeviceIDTotalSize,
|
|
sizeof (VARSTRING),
|
|
TRUE
|
|
))
|
|
{
|
|
ServerFree (pszDeviceClass);
|
|
pParams->lResult = PHONEERR_STRUCTURETOOSMALL;
|
|
goto PGetID_epilog;
|
|
}
|
|
|
|
if ((pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneGetID,
|
|
"phoneGetID",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pID,
|
|
(DWORD) pszDeviceClass,
|
|
(DWORD) pParams->ptClient->hProcess
|
|
|
|
)) == 0)
|
|
{
|
|
//
|
|
// Indicate offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->u.dwDeviceIDOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pID->dwUsedSize;
|
|
}
|
|
|
|
ServerFree (pszDeviceClass);
|
|
}
|
|
|
|
PGetID_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetID"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetLamp(
|
|
PPHONEGETLAMP_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetLamp;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(DWORD) &pParams->dwLampMode
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETLAMP_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetLamp"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetRing(
|
|
PPHONEGETRING_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetRing;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) &pParams->dwRingMode,
|
|
(DWORD) &pParams->dwVolume
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETRING_PARAMS);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetRing"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetStatus(
|
|
PPHONEGETSTATUS_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetStatus;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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;
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) pParams->hPhone;
|
|
LPPHONESTATUS pStatus = (LPPHONESTATUS) pDataBuf,
|
|
pStatus2 = (LPPHONESTATUS) NULL;
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure for the specified API
|
|
// version, verify client's buffer is big enough
|
|
//
|
|
|
|
dwAPIVersion = ptPhoneClient->dwAPIVersion;
|
|
|
|
dwTotalSize = pParams->u.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_epilog;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the fixed size of the structure expected by the SP
|
|
//
|
|
|
|
dwSPIVersion = ptPhoneClient->ptPhone->dwSPIVersion;
|
|
|
|
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_epilog;
|
|
}
|
|
|
|
pStatus = pStatus2;
|
|
dwTotalSize = dwFixedSizeSP;
|
|
}
|
|
|
|
|
|
InitTapiStruct(
|
|
pStatus,
|
|
dwTotalSize,
|
|
dwFixedSizeSP,
|
|
(pStatus2 == NULL ? TRUE : FALSE)
|
|
);
|
|
|
|
if ((pParams->lResult = CallSP2(
|
|
pfnTSPI_phoneGetStatus,
|
|
"phoneGetStatus",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pStatus
|
|
|
|
)) == 0)
|
|
{
|
|
DWORD dwRemainingSize = (pStatus->dwTotalSize -
|
|
pStatus->dwUsedSize),
|
|
dwNeededSize = 0, dwXxxSize;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
#if DBG
|
|
//
|
|
// Verify the info returned by the provider
|
|
//
|
|
|
|
#endif
|
|
|
|
//
|
|
// Add the fields we're responsible for
|
|
//
|
|
|
|
/*
|
|
// BUGBUG PGetStatus: dwNumOwners, ...
|
|
|
|
pStatus->dwNumOwners =
|
|
pStatus->dwNumMonitors =
|
|
|
|
dwNeededSize += (dwXxxSize = ptPhoneApp->dwAppNameSize);
|
|
|
|
if (dwXxxSize < dwRemainingSize)
|
|
{
|
|
pStatus->dwOwnerNameSize = dwXxxSize;
|
|
pStatus->dwOwnerNameOffset = pStatus->dwUsedSize;
|
|
|
|
CopyMemory(
|
|
((LPBYTE) pStatus) + pCallInfo->dwOwnerNameOffset,
|
|
ptPhoneApp->szAppName,
|
|
dwXxxSize
|
|
);
|
|
|
|
pStatus->dwUsedSize += dwXxxSize;
|
|
|
|
dwRemainingSize -= dwXxxSize;
|
|
}
|
|
|
|
|
|
pStatus->dwNeededSize += dwNeededSize;
|
|
*/
|
|
|
|
//
|
|
// 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->u.dwPhoneStatusTotalSize;
|
|
pStatus->dwUsedSize = dwFixedSizeClient;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate the offset & how many bytes of data we're passing back
|
|
//
|
|
|
|
pParams->u.dwPhoneStatusOffset = 0;
|
|
|
|
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pStatus->dwUsedSize;
|
|
}
|
|
}
|
|
|
|
PGetStatus_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetStatus"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetStatusMessages(
|
|
PPHONEGETSTATUSMESSAGES_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // req'd privileges (call only)
|
|
&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
|
|
"GetStatusMessages" // func name
|
|
|
|
)) == 0)
|
|
{
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) pParams->hPhone;
|
|
|
|
|
|
pParams->dwPhoneStates = ptPhoneClient->dwPhoneStates;
|
|
pParams->dwButtonModes = ptPhoneClient->dwButtonModes;
|
|
pParams->dwButtonStates = ptPhoneClient->dwButtonStates;
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEGETSTATUSMESSAGES_PARAMS);
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetStatusMessages"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PGetVolume(
|
|
PPHONEGETVOLUME_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneGetVolume;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) &pParams->dwVolume
|
|
|
|
)) == 0)
|
|
{
|
|
*pdwNumBytesReturned = sizeof (PHONEGETVOLUME_PARAMS);
|
|
}
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"GetVolume"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PInitialize(
|
|
PPHONEINITIALIZE_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
DWORD dwFriendlyNameSize, dwModuleNameSize;
|
|
HANDLE hMutex;
|
|
PTCLIENT ptClient = pParams->ptClient;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
|
|
//
|
|
// 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
|
|
)) ||
|
|
|
|
!(ptPhoneApp->hMutex = MyCreateMutex()))
|
|
{
|
|
pParams->lResult = PHONEERR_NOMEM;
|
|
|
|
goto PInitialize_error1;
|
|
}
|
|
|
|
ptPhoneApp->dwKey = TPHONEAPP_KEY;
|
|
ptPhoneApp->ptClient = ptClient;
|
|
ptPhoneApp->lpfnCallback = pParams->lpfnCallback;
|
|
ptPhoneApp->dwAPIVersion = pParams->dwAPIVersion;
|
|
|
|
ptPhoneApp->pszFriendlyName = (WCHAR *) (ptPhoneApp + 1);
|
|
|
|
lstrcpyW(
|
|
ptPhoneApp->pszFriendlyName,
|
|
(PWSTR)(pDataBuf + pParams->dwFriendlyNameOffset)
|
|
);
|
|
|
|
ptPhoneApp->pszModuleName = (PWSTR)((BYTE *) (ptPhoneApp + 1) + dwFriendlyNameSize);
|
|
|
|
lstrcpyW(
|
|
ptPhoneApp->pszModuleName,
|
|
(PWSTR)(pDataBuf + pParams->dwModuleNameOffset)
|
|
);
|
|
|
|
|
|
//
|
|
// Safely insert new tPhoneApp at front of tClient's tPhoneApp list
|
|
//
|
|
|
|
if (WaitForExclusiveClientAccess(
|
|
ptClient,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
if ((ptPhoneApp->pNext = ptClient->ptPhoneApps))
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp;
|
|
}
|
|
|
|
ptClient->ptPhoneApps = ptPhoneApp;
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_OPERATIONFAILED;
|
|
goto PInitialize_error1;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if global reinit flag set
|
|
//
|
|
|
|
if (TapiGlobals.bReinit)
|
|
{
|
|
pParams->lResult = PHONEERR_REINIT;
|
|
goto PInitialize_error2;
|
|
}
|
|
|
|
|
|
//
|
|
// See if we need to go thru init
|
|
//
|
|
|
|
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
|
|
|
|
if ((TapiGlobals.dwNumLineInits == 0) &&
|
|
(TapiGlobals.dwNumPhoneInits == 0))
|
|
{
|
|
if ((pParams->lResult = ServerInit()) != 0)
|
|
{
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
goto PInitialize_error2;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Fill in the return values
|
|
//
|
|
|
|
pParams->hPhoneApp = (HPHONEAPP) ptPhoneApp;
|
|
pParams->dwNumDevs = TapiGlobals.dwNumPhones;
|
|
|
|
|
|
//
|
|
// Increment total num phone inits
|
|
//
|
|
|
|
TapiGlobals.dwNumPhoneInits++;
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEINITIALIZE_PARAMS);
|
|
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
|
|
goto PInitialize_return;
|
|
|
|
PInitialize_error2:
|
|
|
|
if (WaitForExclusiveClientAccess(
|
|
ptClient,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
INFINITE
|
|
))
|
|
{
|
|
if (ptPhoneApp->pNext)
|
|
{
|
|
ptPhoneApp->pNext->pPrev = ptPhoneApp->pPrev;
|
|
}
|
|
|
|
if (ptPhoneApp->pPrev)
|
|
{
|
|
ptPhoneApp->pPrev->pNext = ptPhoneApp->pNext;
|
|
}
|
|
else
|
|
{
|
|
ptClient->ptPhoneApps = ptPhoneApp->pNext;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
}
|
|
|
|
PInitialize_error1:
|
|
|
|
if (ptPhoneApp)
|
|
{
|
|
if (ptPhoneApp->hMutex)
|
|
{
|
|
CloseHandle (ptPhoneApp->hMutex);
|
|
}
|
|
|
|
ServerFree (ptPhoneApp);
|
|
}
|
|
|
|
PInitialize_return:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"phoneInitialize: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PNegotiateAPIVersion(
|
|
PPHONENEGOTIATEAPIVERSION_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
//
|
|
// Note: TAPI_VERSION1_0 <= dwNegotiatedAPIVersion <= dwSPIVersion
|
|
//
|
|
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
|
|
|
|
if (TapiGlobals.dwNumPhoneInits == 0)
|
|
{
|
|
pParams->lResult = PHONEERR_UNINITIALIZED;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
if (dwDeviceID < TapiGlobals.dwNumPhones)
|
|
{
|
|
DWORD dwAPIHighVersion = pParams->dwAPIHighVersion,
|
|
dwAPILowVersion = pParams->dwAPILowVersion,
|
|
dwHighestValidAPIVersion;
|
|
PTPHONEAPP ptPhoneApp = (PTPHONEAPP) pParams->hPhoneApp;
|
|
|
|
|
|
if (!IsValidPhoneApp ((HPHONEAPP) ptPhoneApp, pParams->ptClient))
|
|
{
|
|
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_exit;
|
|
}
|
|
|
|
|
|
//
|
|
// 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_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
|
|
{
|
|
DBGOUT((1, " Incompatible version"));
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwHighestValidAPIVersion = TAPI_VERSION_CURRENT;
|
|
}
|
|
|
|
|
|
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
|
|
|
|
//
|
|
// WARNING!!! WARNING!!! WARNING!!! WARNING!!!
|
|
// This code overwrites ptPhoneApp and later invalidates it.
|
|
// Do NOT use ptPhoneApp after the MyReleaseMutex call.
|
|
//
|
|
|
|
if ((ptPhoneApp = WaitForExclusivePhoneAppAccess(
|
|
pParams->hPhoneApp,
|
|
pParams->ptClient,
|
|
&hMutex,
|
|
&bCloseMutex,
|
|
INFINITE
|
|
)))
|
|
{
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
MyReleaseMutex (hMutex, bCloseMutex);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALAPPHANDLE;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// See if there's a valid match with the SPI ver
|
|
//
|
|
|
|
{
|
|
DWORD dwSPIVersion;
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
|
|
|
|
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
|
|
dwSPIVersion = pLookupEntry->dwSPIVersion;
|
|
|
|
if (pLookupEntry->bRemoved)
|
|
{
|
|
DBGOUT((1, " phone removed..."));
|
|
pParams->lResult = PHONEERR_NODEVICE;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
if (pLookupEntry->ptProvider == NULL)
|
|
{
|
|
DBGOUT((1, " Provider == NULL"));
|
|
pParams->lResult = PHONEERR_NODRIVER;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
|
|
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,
|
|
(DWORD) pDataBuf
|
|
|
|
)) != 0)
|
|
{
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FillMemory (pDataBuf, sizeof (PHONEEXTENSIONID), 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGOUT((1, " API version too high"));
|
|
pParams->lResult = PHONEERR_INCOMPATIBLEAPIVERSION;
|
|
goto PNegotiateAPIVersion_exit;
|
|
}
|
|
}
|
|
|
|
pParams->dwExtensionIDOffset = 0;
|
|
pParams->dwSize = sizeof (PHONEEXTENSIONID);
|
|
|
|
DBGOUT((4, " ExtensionID0=x%08lx", *(LPDWORD)(pDataBuf+0) ));
|
|
DBGOUT((4, " ExtensionID1=x%08lx", *(LPDWORD)(pDataBuf+4) ));
|
|
DBGOUT((4, " ExtensionID2=x%08lx", *(LPDWORD)(pDataBuf+8) ));
|
|
DBGOUT((4, " ExtensionID3=x%08lx", *(LPDWORD)(pDataBuf+12) ));
|
|
|
|
*pdwNumBytesReturned = sizeof (PHONEEXTENSIONID) + sizeof (TAPI32_MSG);
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_BADDEVICEID;
|
|
}
|
|
|
|
PNegotiateAPIVersion_exit:
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"phoneNegotiateAPIVersion: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PNegotiateExtVersion(
|
|
PPHONENEGOTIATEEXTVERSION_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
DWORD dwDeviceID = pParams->dwDeviceID;
|
|
HANDLE hMutex;
|
|
TSPIPROC pfnTSPI_phoneNegotiateExtVersion;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->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,
|
|
(DWORD) &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(
|
|
PPHONEOPEN_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex,
|
|
bReleasetPhoneMutex = FALSE;
|
|
LONG lResult;
|
|
DWORD dwDeviceID = pParams->dwDeviceID, dwNumMonitors;
|
|
HANDLE hMutex;
|
|
PTPHONE ptPhone = NULL;
|
|
PTPHONECLIENT ptPhoneClient = NULL;
|
|
PTPHONELOOKUPENTRY pLookupEntry;
|
|
|
|
|
|
if ((lResult = PHONEPROLOG(
|
|
pParams->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)
|
|
{
|
|
BOOL bOpenedtPhone = FALSE;
|
|
DWORD dwPrivilege = pParams->dwPrivilege,
|
|
dwExtVersion = pParams->dwExtVersion;
|
|
PTPROVIDER ptProvider;
|
|
|
|
|
|
//
|
|
// Check if the global reinit flag is set
|
|
//
|
|
|
|
if (TapiGlobals.bReinit)
|
|
{
|
|
lResult = PHONEERR_REINIT;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Validate params
|
|
//
|
|
|
|
if ((dwPrivilege != PHONEPRIVILEGE_MONITOR) &&
|
|
(dwPrivilege != PHONEPRIVILEGE_OWNER))
|
|
{
|
|
lResult = PHONEERR_INVALPRIVILEGE;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
pLookupEntry = GetPhoneLookupEntry (dwDeviceID);
|
|
|
|
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;
|
|
}
|
|
|
|
ptPhoneClient->hMutex = MyCreateMutex();
|
|
ptPhoneClient->ptClient = pParams->ptClient;
|
|
ptPhoneClient->ptPhoneApp = (PTPHONEAPP) pParams->hPhoneApp;
|
|
ptPhoneClient->hRemotePhone = (pParams->hRemotePhone ?
|
|
(DWORD) pParams->hRemotePhone : (DWORD) ptPhoneClient);
|
|
ptPhoneClient->dwAPIVersion = pParams->dwAPIVersion;
|
|
ptPhoneClient->dwPrivilege = pParams->dwPrivilege;
|
|
ptPhoneClient->dwCallbackInstance = pParams->dwCallbackInstance;
|
|
|
|
|
|
//
|
|
// Grab the tPhone's mutex, then start doing the open
|
|
//
|
|
|
|
POpen_waitForMutex:
|
|
|
|
if (WaitForSingleObject (pLookupEntry->hMutex, INFINITE)
|
|
!= WAIT_OBJECT_0)
|
|
{
|
|
DBGOUT((1, "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 (pLookupEntry->hMutex);
|
|
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_INVALPRIVILEGE;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
|
|
if (ptPhone == NULL)
|
|
{
|
|
if (!(ptPhone = ServerAlloc (sizeof(TPHONE))))
|
|
{
|
|
lResult = PHONEERR_NOMEM;
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptPhone->hMutex = pLookupEntry->hMutex;
|
|
ptPhone->ptProvider = ptProvider;
|
|
ptPhone->dwDeviceID = pParams->dwDeviceID;
|
|
ptPhone->dwSPIVersion = pLookupEntry->dwSPIVersion;
|
|
|
|
if ((lResult = CallSP5(
|
|
ptProvider->apfn[SP_PHONEOPEN],
|
|
"phoneOpen",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) pParams->dwDeviceID,
|
|
(DWORD) ptPhone,
|
|
(DWORD) &ptPhone->hdPhone,
|
|
(DWORD) pLookupEntry->dwSPIVersion,
|
|
(DWORD) PhoneEventProcSP
|
|
|
|
)) != 0)
|
|
{
|
|
ServerFree (ptPhone);
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
bOpenedtPhone = TRUE;
|
|
}
|
|
|
|
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 ((lResult = CallSP2(
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) ptPhone->hdPhone,
|
|
(DWORD) dwExtVersion
|
|
|
|
)) != 0)
|
|
{
|
|
if (bOpenedtPhone)
|
|
{
|
|
CallSP1(
|
|
ptProvider->apfn[SP_PHONECLOSE],
|
|
"phoneClose",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) ptPhone->hdPhone
|
|
);
|
|
|
|
ServerFree (ptPhone);
|
|
}
|
|
|
|
goto POpen_cleanup;
|
|
}
|
|
|
|
ptPhone->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 (pLookupEntry->hMutex);
|
|
|
|
bReleasetPhoneMutex = FALSE;
|
|
|
|
|
|
//
|
|
// Safely add the new tLineClient to the tLineApp's list
|
|
//
|
|
|
|
{
|
|
BOOL bDupedMutex;
|
|
HANDLE hMutex;
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
if ((ptPhoneApp = WaitForExclusivePhoneAppAccess(
|
|
pParams->hPhoneApp,
|
|
pParams->ptClient,
|
|
&hMutex,
|
|
&bDupedMutex,
|
|
INFINITE
|
|
)))
|
|
{
|
|
if ((ptPhoneClient->pNextSametPhoneApp =
|
|
ptPhoneApp->ptPhoneClients))
|
|
{
|
|
ptPhoneClient->pNextSametPhoneApp->pPrevSametPhoneApp =
|
|
ptPhoneClient;
|
|
}
|
|
|
|
ptPhoneApp->ptPhoneClients = ptPhoneClient;
|
|
|
|
ptPhoneClient->dwKey = TPHONECLIENT_KEY;
|
|
|
|
MyReleaseMutex (hMutex, bDupedMutex);
|
|
|
|
|
|
//
|
|
// 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
|
|
);
|
|
|
|
|
|
//
|
|
// Fill in the return values
|
|
//
|
|
|
|
pParams->hPhone = (HPHONE) ptPhoneClient;
|
|
*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 (pLookupEntry->hMutex, 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)
|
|
{
|
|
ptPhone->dwExtVersion = 0;
|
|
|
|
CallSP2(
|
|
ptProvider->apfn[SP_PHONESELECTEXTVERSION],
|
|
"phoneSelectExtVersion",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) ptPhone->hdPhone,
|
|
(DWORD) 0
|
|
);
|
|
}
|
|
}
|
|
|
|
ReleaseMutex (pLookupEntry->hMutex);
|
|
|
|
DestroytPhone (ptPhone, FALSE); // conditional destroy
|
|
}
|
|
}
|
|
}
|
|
|
|
POpen_cleanup:
|
|
|
|
if (bReleasetPhoneMutex)
|
|
{
|
|
ReleaseMutex (pLookupEntry->hMutex);
|
|
}
|
|
|
|
if (lResult != 0)
|
|
{
|
|
if (ptPhoneClient)
|
|
{
|
|
if (ptPhoneClient->hMutex)
|
|
{
|
|
CloseHandle (ptPhoneClient->hMutex);
|
|
}
|
|
|
|
ServerFree (ptPhoneClient);
|
|
}
|
|
}
|
|
|
|
pParams->lResult = lResult;
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"Open"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetButtonInfo(
|
|
PPHONESETBUTTONINFO_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetButtonInfo;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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;
|
|
|
|
|
|
try
|
|
{
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) pParams->hPhone;
|
|
|
|
|
|
dwAPIVersion = ptPhoneClient->dwAPIVersion;
|
|
dwSPIVersion = ptPhoneClient->ptPhone->dwSPIVersion;
|
|
}
|
|
myexcept
|
|
{
|
|
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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(DWORD) pButtonInfoSP
|
|
);
|
|
|
|
if (pButtonInfoSP != pButtonInfoApp)
|
|
{
|
|
ServerFree (pButtonInfoSP);
|
|
}
|
|
}
|
|
|
|
PSetButtonInfo_epilog:
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetButtonInfo"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetData(
|
|
PPHONESETDATA_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetData;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwDataID,
|
|
(DWORD) (pParams->dwSize ? pDataBuf + pParams->dwDataOffset :NULL),
|
|
(DWORD) pParams->dwSize
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetData"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetDisplay(
|
|
PPHONESETDISPLAY_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetDisplay;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwRow,
|
|
(DWORD) pParams->dwColumn,
|
|
(DWORD) (pParams->dwSize ?
|
|
pDataBuf + pParams->dwDisplayOffset : NULL),
|
|
(DWORD) pParams->dwSize
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetDisplay"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetGain(
|
|
PPHONESETGAIN_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetGain;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) (pParams->dwGain > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwGain)
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetGain"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetHookSwitch(
|
|
PPHONESETHOOKSWITCH_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetHookSwitch;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDevs,
|
|
(DWORD) pParams->dwHookSwitchMode
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetHookSwitch"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetLamp(
|
|
PPHONESETLAMP_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetLamp;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwButtonLampID,
|
|
(DWORD) pParams->dwLampMode
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetLamp"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetRing(
|
|
PPHONESETRING_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetRing;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwRingMode,
|
|
(DWORD) (pParams->dwVolume > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwVolume)
|
|
);
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetRing"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetStatusMessages(
|
|
PPHONESETSTATUSMESSAGES_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
TSPIPROC pfnTSPI_phoneSetStatusMessages;
|
|
|
|
|
|
if ((pParams->lResult = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_MONITOR, // 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 dwUnionPhoneStates, dwUnionButtonModes,
|
|
dwUnionButtonStates;
|
|
PTPHONECLIENT ptPhoneClient = (PTPHONECLIENT) pParams->hPhone;
|
|
PTPHONE ptPhone = ptPhoneClient->ptPhone;
|
|
|
|
|
|
//
|
|
// Validate the params
|
|
//
|
|
|
|
{
|
|
DWORD dwValidPhoneStates, dwValidButtonStates;
|
|
|
|
|
|
switch (ptPhoneClient->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_epilog;
|
|
}
|
|
|
|
if ((pParams->dwButtonStates & ~dwValidButtonStates))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONSTATE;
|
|
goto PSetStatusMessages_epilog;
|
|
}
|
|
|
|
if ((pParams->dwButtonModes & ~AllButtonModes))
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONMODE;
|
|
goto PSetStatusMessages_epilog;
|
|
}
|
|
|
|
if (pParams->dwButtonModes && !pParams->dwButtonStates)
|
|
{
|
|
pParams->lResult = PHONEERR_INVALBUTTONSTATE;
|
|
goto PSetStatusMessages_epilog;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the REINIT bit is always set
|
|
//
|
|
|
|
pParams->dwPhoneStates |= PHONESTATE_REINIT;
|
|
|
|
|
|
//
|
|
// Determine the new states union of all the phone clients
|
|
//
|
|
|
|
dwUnionPhoneStates = pParams->dwPhoneStates;
|
|
dwUnionButtonModes = pParams->dwButtonModes;
|
|
dwUnionButtonStates = pParams->dwButtonStates;
|
|
|
|
{
|
|
PTPHONECLIENT ptPhoneClientTmp = ptPhone->ptPhoneClients;
|
|
|
|
|
|
while (ptPhoneClientTmp)
|
|
{
|
|
if (ptPhoneClientTmp != ptPhoneClient)
|
|
{
|
|
dwUnionPhoneStates = ptPhoneClientTmp->dwPhoneStates;
|
|
dwUnionButtonModes = ptPhoneClientTmp->dwButtonModes;
|
|
dwUnionButtonStates = ptPhoneClientTmp->dwButtonStates;
|
|
}
|
|
|
|
ptPhoneClientTmp = ptPhoneClientTmp->pNextSametPhone;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the new states union is the same as previous states union
|
|
// just reset the fields in the tPhoneClient, else call the provider
|
|
//
|
|
|
|
if (((dwUnionPhoneStates == ptPhone->dwUnionPhoneStates) &&
|
|
(dwUnionButtonModes == ptPhone->dwUnionButtonModes) &&
|
|
(dwUnionButtonStates == ptPhone->dwUnionButtonStates)) ||
|
|
|
|
((pParams->lResult = CallSP4(
|
|
pfnTSPI_phoneSetStatusMessages,
|
|
"phoneSetStatusMessages",
|
|
SP_FUNC_SYNC,
|
|
(DWORD) hdPhone,
|
|
(DWORD) dwUnionPhoneStates,
|
|
(DWORD) dwUnionButtonModes,
|
|
(DWORD) dwUnionButtonStates
|
|
|
|
)) == 0))
|
|
{
|
|
ptPhoneClient->dwPhoneStates = pParams->dwPhoneStates;
|
|
ptPhoneClient->dwButtonModes = pParams->dwButtonModes;
|
|
ptPhoneClient->dwButtonStates = pParams->dwButtonStates;
|
|
|
|
ptPhone->dwUnionPhoneStates = dwUnionPhoneStates;
|
|
ptPhone->dwUnionButtonModes = dwUnionButtonModes;
|
|
ptPhone->dwUnionButtonStates = dwUnionButtonStates;
|
|
}
|
|
}
|
|
|
|
PSetStatusMessages_epilog:
|
|
|
|
PHONEEPILOGSYNC(
|
|
&pParams->lResult,
|
|
hMutex,
|
|
bCloseMutex,
|
|
"SetStatusMessages"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PSetVolume(
|
|
PPHONESETVOLUME_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
BOOL bCloseMutex;
|
|
LONG lRequestID;
|
|
HANDLE hMutex;
|
|
HDRVPHONE hdPhone;
|
|
PASYNCREQUESTINFO pAsyncRequestInfo;
|
|
TSPIPROC pfnTSPI_phoneSetVolume;
|
|
|
|
|
|
if ((lRequestID = PHONEPROLOG(
|
|
pParams->ptClient, // tClient
|
|
ANY_RT_HPHONE, // widget type
|
|
(DWORD) pParams->hPhone, // client widget handle
|
|
(LPVOID) &hdPhone, // provider widget handle
|
|
PHONEPRIVILEGE_OWNER, // 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,
|
|
(DWORD) hdPhone,
|
|
(DWORD) pParams->dwHookSwitchDev,
|
|
(DWORD) (pParams->dwVolume > 0x0000ffff ?
|
|
0x0000ffff : pParams->dwVolume)
|
|
);
|
|
}
|
|
}
|
|
|
|
PHONEEPILOGASYNC(
|
|
&pParams->lResult,
|
|
lRequestID,
|
|
hMutex,
|
|
bCloseMutex,
|
|
pAsyncRequestInfo,
|
|
"SetVolume"
|
|
);
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
PShutdown(
|
|
PPHONESHUTDOWN_PARAMS pParams,
|
|
LPBYTE pDataBuf,
|
|
LPDWORD pdwNumBytesReturned
|
|
)
|
|
{
|
|
PTPHONEAPP ptPhoneApp;
|
|
|
|
|
|
WaitForSingleObject (TapiGlobals.hMutex, INFINITE);
|
|
|
|
if (!(ptPhoneApp = IsValidPhoneApp (pParams->hPhoneApp, pParams->ptClient)))
|
|
{
|
|
if (TapiGlobals.dwNumPhoneInits == 0)
|
|
{
|
|
pParams->lResult = PHONEERR_UNINITIALIZED;
|
|
}
|
|
else
|
|
{
|
|
pParams->lResult = PHONEERR_INVALAPPHANDLE;
|
|
}
|
|
}
|
|
|
|
ReleaseMutex (TapiGlobals.hMutex);
|
|
|
|
if (pParams->lResult == 0)
|
|
{
|
|
DestroytPhoneApp ((PTPHONEAPP) pParams->hPhoneApp);
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
char szResult[32];
|
|
|
|
|
|
DBGOUT((
|
|
3,
|
|
"phoneShutdown: exit, result=%s",
|
|
MapResultCodeToText (pParams->lResult, szResult)
|
|
));
|
|
}
|
|
#endif
|
|
}
|