/*++ Copyright (c) 1997 Microsoft Corporation Module Name: tapimmc.c Abstract: Client-side implementation of TAPI MMC support APIs Author: Dan Knudson (DanKn) 10-Dec-1997 Revision History: Notes: --*/ #include "windows.h" #include "stdarg.h" #include "stdio.h" #include "tapi.h" #include "tspi.h" #include "utils.h" #include "tapimmc.h" #include "client.h" #include "clntprivate.h" #include "tapsrv.h" #include "lmcons.h" #include "resource.h" #define MMCAPP_KEY ((DWORD) 'CmMt') typedef struct _MMCAPP { DWORD dwKey; BOOL bLocal; HLINEAPP hLineApp; DWORD dwAPIVersion; HANDLE hReinitializeEvent; PCONTEXT_HANDLE_TYPE phCtx; // RPC handle context BOOL bNoServiceControl; } MMCAPP, *PMMCAPP; LONG WINAPI FreeClientResources( void ); PMMCAPP PASCAL IsValidMmcApp( HMMCAPP hMmcApp ) { PMMCAPP pMmcApp = NULL; try { if (((PMMCAPP) hMmcApp)->dwKey == MMCAPP_KEY) { pMmcApp = (PMMCAPP) hMmcApp; } } except (EXCEPTION_EXECUTE_HANDLER) { // do nothing } return pMmcApp; } LONG WINAPI MMCAddProvider( HMMCAPP hMmcApp, HWND hwndOwner, LPCWSTR lpszProviderFilename, LPDWORD lpdwProviderID ) { LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { lResult = lineAddProviderW( lpszProviderFilename, hwndOwner, lpdwProviderID ); } else { // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = lineAddProviderW( lpszProviderFilename, hwndOwner, lpdwProviderID ); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCConfigProvider( HMMCAPP hMmcApp, HWND hwndOwner, DWORD dwProviderID ) { LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { lResult = lineConfigProvider (hwndOwner, dwProviderID); } else { // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = lineConfigProvider (hwndOwner, dwProviderID); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCGetAvailableProviders( HMMCAPP hMmcApp, LPAVAILABLEPROVIDERLIST lpProviderList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mGetAvailableProviders), { (ULONG_PTR) 0, (ULONG_PTR) lpProviderList }, { hXxxApp, lpGet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "GetAvailableProviders"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "GetAvailableProviders"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCGetLineInfo( HMMCAPP hMmcApp, LPDEVICEINFOLIST lpDeviceInfoList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mGetLineInfo), { (ULONG_PTR) 0, (ULONG_PTR) lpDeviceInfoList }, { hXxxApp, lpGet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "GetLineInfo"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "GetLineInfo"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } #define MAX_DEFAULT_STATUS 64 extern HINSTANCE g_hInst; LONG WINAPI MMCGetLineStatus( HMMCAPP hMmcApp, HWND hwndOwner, DWORD dwStatusLevel, DWORD dwProviderID, DWORD dwPermanentLineID, LPVARSTRING lpStatusBuffer ) { static WCHAR szDefStatus[MAX_DEFAULT_STATUS] = L""; static int cbCount; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { return LINEERR_INVALAPPHANDLE; } if (!lpStatusBuffer || IsBadWritePtr (lpStatusBuffer, sizeof (*lpStatusBuffer))) { return LINEERR_INVALPOINTER; } if (lpStatusBuffer->dwTotalSize < sizeof (*lpStatusBuffer)) { return LINEERR_STRUCTURETOOSMALL; } if (0 == cbCount || 0 == szDefStatus[0]) { cbCount = LoadString (g_hInst, IDS_DEFAULT_STATUS, szDefStatus, MAX_DEFAULT_STATUS); cbCount = (cbCount+1)<<1; // + 1 because LoadString does not count the terminating NULL; // <<1 because we need the size in bytes, not characters, and WCHAR is 2 bytes. } lpStatusBuffer->dwNeededSize = sizeof (*lpStatusBuffer) + cbCount; if (lpStatusBuffer->dwTotalSize >= lpStatusBuffer->dwNeededSize) { lpStatusBuffer->dwStringFormat = STRINGFORMAT_UNICODE; lpStatusBuffer->dwStringSize = cbCount; lpStatusBuffer->dwStringOffset = sizeof (*lpStatusBuffer); wcscpy ((WCHAR *) (lpStatusBuffer + 1), szDefStatus); } else { lpStatusBuffer->dwUsedSize = sizeof (*lpStatusBuffer); lpStatusBuffer->dwStringFormat = lpStatusBuffer->dwStringSize = lpStatusBuffer->dwStringOffset = 0; } return 0; } LONG WINAPI MMCGetPhoneInfo( HMMCAPP hMmcApp, LPDEVICEINFOLIST lpDeviceInfoList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mGetPhoneInfo), { (ULONG_PTR) 0, (ULONG_PTR) lpDeviceInfoList }, { hXxxApp, lpGet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "GetPhoneInfo"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "GetPhoneInfo"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCGetPhoneStatus( HMMCAPP hMmcApp, HWND hwndOwner, DWORD dwStatusLevel, DWORD dwProviderID, DWORD dwPermanentLineID, LPVARSTRING lpStatusBuffer ) { static WCHAR szDefStatus[MAX_DEFAULT_STATUS] = L""; static int cbCount; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { return LINEERR_INVALAPPHANDLE; } if (!lpStatusBuffer || IsBadWritePtr (lpStatusBuffer, sizeof (*lpStatusBuffer))) { return LINEERR_INVALPOINTER; } if (lpStatusBuffer->dwTotalSize < sizeof (*lpStatusBuffer)) { return LINEERR_STRUCTURETOOSMALL; } if (0 == cbCount || 0 == szDefStatus[0]) { cbCount = LoadString (g_hInst, IDS_DEFAULT_STATUS, szDefStatus, MAX_DEFAULT_STATUS); cbCount = (cbCount+1)<<1; // + 1 because LoadString does not count the terminating NULL; // <<1 because we need the size in bytes, not characters, and WCHAR is 2 bytes. } lpStatusBuffer->dwNeededSize = sizeof (*lpStatusBuffer) + cbCount; if (lpStatusBuffer->dwTotalSize >= lpStatusBuffer->dwNeededSize) { lpStatusBuffer->dwStringFormat = STRINGFORMAT_UNICODE; lpStatusBuffer->dwStringSize = cbCount; lpStatusBuffer->dwStringOffset = sizeof (*lpStatusBuffer); wcscpy ((WCHAR *) (lpStatusBuffer + 1), szDefStatus); } else { lpStatusBuffer->dwUsedSize = sizeof (*lpStatusBuffer); lpStatusBuffer->dwStringFormat = lpStatusBuffer->dwStringSize = lpStatusBuffer->dwStringOffset = 0; } return 0; } LONG WINAPI MMCGetProviderList( HMMCAPP hMmcApp, LPLINEPROVIDERLIST lpProviderList ) { LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { lResult = lineGetProviderListW( pMmcApp->dwAPIVersion, lpProviderList ); } else { // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = lineGetProviderListW( pMmcApp->dwAPIVersion, lpProviderList ); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCGetServerConfig( HMMCAPP hMmcApp, LPTAPISERVERCONFIG lpConfig ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mGetServerConfig), { (ULONG_PTR) 0, (ULONG_PTR) lpConfig }, { hXxxApp, lpGet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "GetServerConfig"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "GetServerConfig"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } if (lpConfig && pMmcApp && pMmcApp->bNoServiceControl) { lpConfig->dwFlags |= TAPISERVERCONFIGFLAGS_NOSERVICECONTROL; } ExitHere: return lResult; } LONG WINAPI EnsureTapiService(LPCWSTR lpszComputerName, DWORD * pdwServiceState) { SC_HANDLE hSCMgr = NULL; SC_HANDLE hTapiSrv = NULL; LONG lResult = 0; DWORD dwNumSecondsSleptStartPending = 0, dwNumSecondsSleptStopPending = 0; SERVICE_STATUS status; BOOL bBreakOut = FALSE; if ((hSCMgr = OpenSCManagerW( lpszComputerName, // Machine name NULL, // ServicesActive database SC_MANAGER_CONNECT // desired access )) == NULL) { lResult = GetLastError(); LOG((TL_ERROR, "OpenSCManager failed, err=%d", lResult)); goto ExitHere; } if ((hTapiSrv = OpenServiceW( hSCMgr, // SC mgr handle L"TAPISRV", // name of service to open SERVICE_START | // desired access SERVICE_QUERY_STATUS | SERVICE_STOP | SERVICE_CHANGE_CONFIG )) == NULL) { lResult = GetLastError() | 0x80000000; LOG((TL_ERROR, "OpenService failed, err=%d", GetLastError())); goto ExitHere; } while (1) { QueryServiceStatus (hTapiSrv, &status); switch (status.dwCurrentState) { case SERVICE_RUNNING: LOG((TL_INFO, "Tapisrv running")); bBreakOut = TRUE; break; case SERVICE_START_PENDING: Sleep (1000); if (++dwNumSecondsSleptStartPending > 180) { // Wait for no longer than 3 minutes LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_START_PENDING")); bBreakOut = TRUE; } break; case SERVICE_STOP_PENDING: Sleep (1000); if (++dwNumSecondsSleptStopPending > 180) { // Wait for no more than 3 minutes LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_STOP_PENDING")); bBreakOut = TRUE; } break; case SERVICE_STOPPED: LOG((TL_INFO, "Starting tapisrv (NT)...")); if (!StartService( hTapiSrv, // service handle 0, // num args NULL // args )) { lResult = GetLastError(); if (lResult != ERROR_SERVICE_ALREADY_RUNNING) { LOG((TL_ERROR, "StartService(TapiSrv) failed, err=%d", lResult )); bBreakOut = TRUE; } else { lResult = 0; } } break; default: LOG((TL_ERROR, "error, service status=%d", status.dwCurrentState)); lResult = GetLastError(); bBreakOut = TRUE; break; } if (bBreakOut) { break; } } if (pdwServiceState) { *pdwServiceState = status.dwCurrentState; } ExitHere: if (hSCMgr) CloseServiceHandle(hSCMgr); if (hTapiSrv) CloseServiceHandle(hTapiSrv); return lResult; } LONG WINAPI MMCInitialize( LPCWSTR lpszComputerName, LPHMMCAPP lphMmcApp, LPDWORD lpdwAPIVersion, HANDLE hReinitializeEvent ) { LONG lResult = 0; LONG lSrvResult = 0; DWORD dwSize; WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1] = L""; PMMCAPP pMmcApp; if ((lpszComputerName && IsBadStringPtrW (lpszComputerName, 0xffffffff)) || IsBadWritePtr (lphMmcApp, sizeof (*lphMmcApp)) || IsBadWritePtr (lpdwAPIVersion, sizeof (*lpdwAPIVersion))) { return LINEERR_INVALPOINTER; } if (!(pMmcApp = ClientAlloc (sizeof (*pMmcApp)))) { return LINEERR_NOMEM; } dwSize = sizeof (szComputerName) / sizeof (WCHAR); GetComputerNameW (szComputerName, &dwSize); lSrvResult = EnsureTapiService(lpszComputerName, NULL); if (!lpszComputerName || _wcsicmp (lpszComputerName, szComputerName) == 0) { pMmcApp->bLocal = TRUE; } else { // We need to manage another computer RPC_STATUS status, status2; BOOL bRet; BOOL bException = FALSE; HANDLE hAsyncEventsEvent = NULL; LPWSTR pszStringBinding; WCHAR szUserName[UNLEN + 1]; dwSize = sizeof(szUserName) / sizeof(WCHAR); bRet = GetUserNameW(szUserName, &dwSize); if (!bRet) { lResult = GetLastError(); LOG((TL_ERROR, "GetUserNameW failed: err=%d", lResult)); goto ExitHere; } // Init the RPC connection with the server status = RpcStringBindingComposeW ( NULL, // ObjUuid L"ncacn_np", // ProtSeq (LPWSTR)lpszComputerName, // NetworkAddr L"\\pipe\\tapsrv", // EndPoint NULL, // Options &pszStringBinding); // StringBinding if (status) { LOG((TL_ERROR, "RpcStringBindingCompose failed: err=%d", status)); lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } status = RpcBindingFromStringBindingW( pszStringBinding, // StringBinding &hTapSrv); // Binding status2 = RpcStringFreeW(&pszStringBinding); if (status || status2) { LOG((TL_ERROR, "RpcBindingFromStringBinding failed: err=%d", status)); lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } status = RpcBindingSetAuthInfoW ( hTapSrv, // hBinding NULL, // ServerPrincName RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // AuthnLevel RPC_C_AUTHN_WINNT, // AuthService NULL, // AuthIdentity 0); // AuthzService if (status) { LOG((TL_ERROR, "RpcBindingSetAuthInfo failed: err=%d", status)); RpcBindingFree(hTapSrv); lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } RpcTryExcept { LOG((TL_TRACE, "MMCInitialize: calling ClientAttach...")); lResult = ClientAttach( &(pMmcApp->phCtx), 0xfffffffd, // Indicate to the server this is from MMC client // on another machine (long *)&hAsyncEventsEvent, szUserName, szComputerName ); LOG((TL_TRACE, "MMCInitialize: ClientAttach returned x%x", lResult)); } RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) { LOG((TL_TRACE, "MMCInitialize: ClientAttach caused except=%d", RpcExceptionCode() )); bException = TRUE; } RpcEndExcept status = RpcBindingFree(&hTapSrv); if (status || bException) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } if (lResult) { goto ExitHere; } pMmcApp->bLocal = FALSE; } // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!(pMmcApp->bLocal) && !SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } { DWORD dwNumLines; LINEINITIALIZEEXPARAMS initExParams; initExParams.dwTotalSize = sizeof (initExParams); initExParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT; lResult = lineInitializeExW( &pMmcApp->hLineApp, NULL, NULL, NULL, &dwNumLines, lpdwAPIVersion, &initExParams ); pMmcApp->dwAPIVersion = *lpdwAPIVersion; } // Clear the PCONTEXT_TYPE_HANDLE in TLS if (!(pMmcApp->bLocal) && !SetTlsPCtxHandle(NULL)) { lResult = LINEERR_OPERATIONUNAVAIL; } ExitHere: if (lResult == 0) { pMmcApp->dwKey = MMCAPP_KEY; *lphMmcApp = (HMMCAPP) pMmcApp; } else { ClientFree (pMmcApp); } if (lSrvResult && (lResult == 0)) { // // We have no problem in connecting to the remote computer // but we can not manipulate its TAPI service, i.e start service // tell the app about it. // pMmcApp->bNoServiceControl = TRUE; } return lResult; } LONG WINAPI MMCRemoveProvider( HMMCAPP hMmcApp, HWND hwndOwner, DWORD dwProviderID ) { LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { lResult = lineRemoveProvider (dwProviderID, hwndOwner); } else { // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = lineRemoveProvider (dwProviderID, hwndOwner); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCSetLineInfo( HMMCAPP hMmcApp, LPDEVICEINFOLIST lpDeviceInfoList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mSetLineInfo), { (ULONG_PTR) 0, (ULONG_PTR) lpDeviceInfoList }, { hXxxApp, lpSet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "SetLineInfo"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "SetLineInfo"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCSetPhoneInfo( HMMCAPP hMmcApp, LPDEVICEINFOLIST lpDeviceInfoList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mSetPhoneInfo), { (ULONG_PTR) 0, (ULONG_PTR) lpDeviceInfoList }, { hXxxApp, lpSet_Struct } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "SetPhoneInfo"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "SetPhoneInfo"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCSetServerConfig( HMMCAPP hMmcApp, LPTAPISERVERCONFIG lpConfig ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, mSetServerConfig), { (ULONG_PTR) 0, (ULONG_PTR) lpConfig }, { hXxxApp, lpSet_Struct } }; LONG lResult; DWORD dwFlags; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (lpConfig && pMmcApp) { dwFlags = lpConfig->dwFlags; lpConfig->dwFlags &= (~TAPISERVERCONFIGFLAGS_NOSERVICECONTROL); } if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "SetServerConfig"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "SetServerConfig"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } if (lpConfig && pMmcApp) { lpConfig->dwFlags = dwFlags; } ExitHere: return lResult; } LONG WINAPI MMCGetDeviceFlags( HMMCAPP hMmcApp, BOOL bLine, DWORD dwProviderID, DWORD dwPermanentDeviceID, DWORD * pdwFlags, DWORD * pdwDeviceID ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, mGetDeviceFlags), { (ULONG_PTR) 0, (ULONG_PTR) bLine, (ULONG_PTR) dwProviderID, (ULONG_PTR) dwPermanentDeviceID, (ULONG_PTR) pdwFlags, (ULONG_PTR) pdwDeviceID, }, { hXxxApp, Dword, Dword, Dword, lpDword, lpDword } }; LONG lResult; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; lResult = DOFUNC (&funcArgs, "SetPhoneInfo"); } else { funcArgs.Args[0] = (ULONG_PTR) pMmcApp->hLineApp; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = DOFUNC (&funcArgs, "SetPhoneInfo"); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } } ExitHere: return lResult; } LONG WINAPI MMCShutdown( HMMCAPP hMmcApp ) { LONG lResult = 0; PMMCAPP pMmcApp = IsValidMmcApp (hMmcApp); if (!pMmcApp) { lResult = LINEERR_INVALAPPHANDLE; } else if (pMmcApp->bLocal) { pMmcApp->dwKey = 0xfffffffe; lResult = lineShutdown (pMmcApp->hLineApp); ClientFree (pMmcApp); // // #196350 - After enabling tapi as a server the MMC does a // FreeLibrary on us, thinking that we'll terminate our rpc // connection with the tapisrv, so it can shutdown tapisrv // and restart it w/ different credentials, etc. However, // the MMC is linked with CSCUI.DLL, who in turn links with // a RAS DLL, who in turn links with TAPI32.DLL, therefore // we never actually get unloaded. Since we don't otherwise // deal with the service going down at this point, we want // to manually call FreeClientResources() to make it seem // like we've never been talking to tapisrv. // // Not needed anymore, now lineShutdown closes the RPC connection // FreeClientResources(); } else if (pMmcApp->phCtx) { pMmcApp->dwKey = 0xfffffffe; // Set the PCONTEXT_TYPE_HANDLE for lineInializeExW to use if (!SetTlsPCtxHandle(pMmcApp->phCtx)) { lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; } lResult = lineShutdown (pMmcApp->hLineApp); if (!SetTlsPCtxHandle(NULL) && !lResult) { lResult = LINEERR_OPERATIONUNAVAIL; } RpcTryExcept { ClientDetach (&(pMmcApp->phCtx)); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { // do something? } RpcEndExcept pMmcApp->phCtx = NULL; ClientFree (pMmcApp); } ExitHere: return lResult; }