///////////////////////////////////////////////////////////////////// // // Module: rdpsnd.c // // Purpose: User-mode audio driver for terminal server // audio redirection // // Copyright(C) Microsoft Corporation 2000 // // History: 4-10-2000 vladimis [created] // ///////////////////////////////////////////////////////////////////// #include "rdpsnd.h" #include #include #include #define WINLOGON_EXE L"\\??\\%SystemRoot%\\system32\\winlogon.exe" const CHAR *ALV = "TSSND::ALV - "; const CHAR *INF = "TSSND::INF - "; const CHAR *WRN = "TSSND::WRN - "; const CHAR *ERR = "TSSND::ERR - "; const CHAR *FATAL = "TSSND::FATAL - "; HANDLE g_hHeap = NULL; HANDLE g_hMixerThread = NULL; HINSTANCE g_hDllInst = NULL; BOOL g_bPersonalTS = FALSE; BOOL bInitializedSuccessfully = FALSE; /* * Function: * DllInstanceInit * * Description: * Dll main enrty point * */ BOOL DllInstanceInit( HINSTANCE hDllInst, DWORD dwReason, LPVOID fImpLoad ) { BOOL rv = FALSE; if (DLL_PROCESS_ATTACH == dwReason) { TRC(ALV, "DLL_PROCESS_ATTACH\n"); TSHEAPINIT; if (!TSISHEAPOK) { TRC(FATAL, "DllInstanceInit: can't create heap\n"); goto exitpt; } __try { InitializeCriticalSection(&g_cs); rv = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { rv = FALSE; } if (!rv) { TRC(FATAL, "DllInstanceInit: can't initialize critical section\n"); goto exitpt; } DisableThreadLibraryCalls(hDllInst); g_hDllInst = hDllInst; rv = TRUE; } else if (DLL_PROCESS_DETACH == dwReason) { TRC(ALV, "DLL_PROCESS_DETACH\n"); TSHEAPDESTROY; rv = TRUE; } exitpt: return rv; } BOOL IsPersonalTerminalServicesEnabled( VOID ) { BOOL fRet; DWORDLONG dwlConditionMask; OSVERSIONINFOEX osVersionInfo; RtlZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX)); osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osVersionInfo.wProductType = VER_NT_WORKSTATION; osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS; dwlConditionMask = 0; VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR); fRet = VerifyVersionInfo( &osVersionInfo, VER_PRODUCT_TYPE | VER_SUITENAME, dwlConditionMask ); return(fRet); } BOOL RunningInWinlogon() { WCHAR szWinlogonOrg[128]; WCHAR szFile[128]; static BOOL s_bWinlogonChecked = FALSE; static BOOL s_bWinlogonResult = FALSE; if ( s_bWinlogonChecked ) { goto exitpt; } szWinlogonOrg[0] = 0; if (!ExpandEnvironmentStrings( WINLOGON_EXE, szWinlogonOrg, RTL_NUMBER_OF( szWinlogonOrg ))) { TRC( ERR, "Failed to get winlogon path: GetLastError=%d\n", GetLastError()); goto exitpt; } if ( !GetModuleFileNameEx( GetCurrentProcess(), GetModuleHandle( NULL ), szFile, RTL_NUMBER_OF( szFile ))) { TRC( ERR, "GetModuleFileNameEx failed: GetLastError=%d\n", GetLastError()); goto exitpt; } s_bWinlogonChecked = TRUE; s_bWinlogonResult = ( 0 == _wcsicmp( szFile, szWinlogonOrg )); exitpt: return s_bWinlogonResult; } HANDLE _CreateInitEvent( VOID ) { SECURITY_ATTRIBUTES SA; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[2]; SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY; PSID pSidWorld = NULL; PSID pSidNT = NULL; PACL pNewDAcl = NULL; DWORD dwres; HANDLE hWaitToInit = NULL; // // wait, before creating this event, check if we are running inside winlogon // only then create this event, because only then we have to delay // audio rendering of the logon sound (aka "TADA") // if ( !RunningInWinlogon() ) { goto exitpt; } else { TRC( INF, "running in winlogon, delayed audio rendering\n" ); } pSD = (PSECURITY_DESCRIPTOR) TSMALLOC(SECURITY_DESCRIPTOR_MIN_LENGTH); if ( NULL == pSD ) goto exitpt; if ( !AllocateAndInitializeSid( &siaWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidWorld)) { goto exitpt; } if ( !AllocateAndInitializeSid( &siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidNT )) { goto exitpt; } ZeroMemory(ea, sizeof(ea)); ea[0].grfAccessPermissions = EVENT_MODIFY_STATE; ea[0].grfAccessMode = GRANT_ACCESS; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.ptstrName = (LPTSTR)pSidWorld; ea[1].grfAccessPermissions = GENERIC_ALL; ea[1].grfAccessMode = GRANT_ACCESS; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.ptstrName = (LPTSTR)pSidNT; dwres = SetEntriesInAcl(2, ea, NULL, &pNewDAcl ); if ( ERROR_SUCCESS != dwres ) { goto exitpt; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) goto exitpt; if (!SetSecurityDescriptorDacl(pSD, TRUE, // specifying a disc. ACL pNewDAcl, FALSE)) // not a default disc. ACL goto exitpt; SA.nLength = sizeof( SA ); SA.lpSecurityDescriptor = pSD; SA.bInheritHandle = FALSE; hWaitToInit = CreateEvent( &SA, FALSE, FALSE, TSSND_WAITTOINIT ); if ( NULL == hWaitToInit ) { TRC( ALV, "Failed to create WaitToInit event:%d\n", GetLastError()); } else if ( ERROR_ALREADY_EXISTS == GetLastError() ) { CloseHandle( hWaitToInit ); TRC( ALV, "Init event already exists\n" ); hWaitToInit = NULL; } exitpt: if ( NULL != pNewDAcl ) { LocalFree( pNewDAcl ); } if ( NULL != pSidNT ) { LocalFree( pSidNT ); } if ( NULL != pSidWorld ) { LocalFree( pSidWorld ); } if ( NULL != pSD ) { TSFREE( pSD ); } return hWaitToInit; } /* * Function: * drvEnable * * Description: * Initializes the driver * */ LRESULT drvEnable( VOID ) { LRESULT rv = 1; EnterCriticalSection(&g_cs); if (bInitializedSuccessfully) { rv = 1; goto exitpt; } if ( NULL == g_hDataReadyEvent ) g_hDataReadyEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TSSND_DATAREADYEVENT); if (NULL == g_hDataReadyEvent) { TRC(ALV, "DRV_ENABLE: can't open %S: %d\n", TSSND_DATAREADYEVENT, GetLastError()); rv = 0; } if ( NULL == g_hStreamIsEmptyEvent ) g_hStreamIsEmptyEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TSSND_STREAMISEMPTYEVENT); if (NULL == g_hDataReadyEvent) { TRC(ALV, "DRV_ENABLE: can't open %S: %d\n", TSSND_STREAMISEMPTYEVENT, GetLastError()); rv = 0; } if ( NULL == g_hStreamMutex ) g_hStreamMutex = OpenMutex(SYNCHRONIZE, FALSE, TSSND_STREAMMUTEX); if (NULL == g_hDataReadyEvent) { TRC(ALV, "DRV_ENABLE: can't open %S: %d\n", TSSND_STREAMMUTEX, GetLastError()); rv = 0; } if ( NULL == g_hMixerEvent ) g_hMixerEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (NULL == g_hMixerEvent) { TRC(ERR, "DRV_ENABLE: can't create mixer event: %d\n", GetLastError()); rv = 0; } if ( NULL == g_hStream ) g_hStream = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, TSSND_STREAMNAME ); if (NULL == g_hStream) { TRC(ALV, "Can't open the stream mapping\n"); rv = 0; } if ( (NULL == g_Stream) && (NULL != g_hStream) ) g_Stream = MapViewOfFile( g_hStream, FILE_MAP_ALL_ACCESS, 0, 0, // offset sizeof(*g_Stream) ); if (NULL == g_Stream) { TRC(ALV, "drvEnale: " "can't map the stream view: %d\n", GetLastError()); rv = 0; } g_bPersonalTS = IsPersonalTerminalServicesEnabled(); if ( 1 == rv && NULL != g_Stream && 0 != ( g_Stream->dwSoundCaps & TSSNDCAPS_INITIALIZED )) { rv = _EnableMixerThread(); } exitpt: if (0 != rv) { bInitializedSuccessfully = TRUE; } // // waiting for initialization ? // if (( 0 == rv || NULL == g_Stream || 0 == ( g_Stream->dwSoundCaps & TSSNDCAPS_INITIALIZED )) && !AudioRedirDisabled() && NULL == g_hWaitToInitialize ) { g_hWaitToInitialize = _CreateInitEvent(); } LeaveCriticalSection(&g_cs); return rv; } /* * Function: * drvDisable * * Description: * Driver cleanup * */ LRESULT drvDisable( VOID ) { HANDLE hStreamMutex; EnterCriticalSection(&g_cs); hStreamMutex = g_hStreamMutex; _waveAcquireStream(); TRC( INF, "drvDisable PID(0x%x)\n", GetCurrentProcessId() ); if (NULL == g_hMixerThread || NULL == g_hMixerEvent) goto exitpt; // // Disable the mixer // g_bMixerRunning = FALSE; // // Kick the mixer thread, so it exits // SetEvent(g_hMixerEvent); WaitForSingleObject(g_hMixerThread, INFINITE); exitpt: if ( NULL != g_hWaitToInitialize ) { CloseHandle( g_hWaitToInitialize ); } if (NULL != g_hDataReadyEvent) CloseHandle(g_hDataReadyEvent); if (NULL != g_hStreamIsEmptyEvent) CloseHandle(g_hStreamIsEmptyEvent); if (NULL != g_hMixerEvent) CloseHandle(g_hMixerEvent); if (NULL != g_Stream) UnmapViewOfFile(g_Stream); if (NULL != g_hStream) CloseHandle(g_hStream); if (NULL != g_hMixerThread) CloseHandle(g_hMixerThread); g_hWaitToInitialize = NULL; g_hDataReadyEvent = NULL; g_hStreamIsEmptyEvent = NULL; g_hMixerEvent = NULL; g_hStreamMutex = NULL; g_Stream = NULL; g_hStream = NULL; g_hMixerThread = NULL; g_bMixerRunning = FALSE; bInitializedSuccessfully = FALSE; if (NULL != hStreamMutex) CloseHandle(hStreamMutex); // this will release the stream LeaveCriticalSection(&g_cs); return 1; } /* * Function: * DriverProc * * Description: * Driver main entry point * */ LRESULT DriverProc( DWORD_PTR dwDriverID, HANDLE hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2 ) { LRESULT rv = 0; // Here, we don't do anything but trace and call DefDriverProc // switch (uiMessage) { case DRV_LOAD: TRC(ALV, "DRV_LOAD\n"); rv = 1; break; case DRV_FREE: TRC(ALV, "DRV_FREE\n"); rv = 1; break; case DRV_OPEN: TRC(ALV, "DRV_OPEN\n"); rv = 1; break; case DRV_CLOSE: TRC(ALV, "DRV_CLOSE\n"); rv = 1; break; case DRV_ENABLE: TRC(ALV, "DRV_ENABLE\n"); rv = 1; break; case DRV_DISABLE: TRC(ALV, "DRV_DISABLE\n"); rv = drvDisable(); break; case DRV_QUERYCONFIGURE: TRC(ALV, "DRV_QUERYCONFIGURE\n"); rv = 0; break; case DRV_CONFIGURE: TRC(ALV, "DRV_CONFIGURE\n"); rv = 0; break; default: rv = DefDriverProc( dwDriverID, hDriver, uiMessage, lParam1, lParam2 ); TRC(ALV, "DRV_UNKNOWN(%d): DefDriverProc returned %d\n", uiMessage, rv); } return rv; } VOID _cdecl _DebugMessage( LPCSTR szLevel, LPCSTR szFormat, ... ) { CHAR szBuffer[256]; va_list arglist; if (ALV == szLevel) return; va_start (arglist, szFormat); _vsnprintf (szBuffer, RTL_NUMBER_OF(szBuffer), szFormat, arglist); va_end (arglist); szBuffer[ RTL_NUMBER_OF( szBuffer ) - 1 ] = 0; OutputDebugStringA(szLevel); OutputDebugStringA(szBuffer); }