Windows2003-3790/termsrv/rdpsnd/rdpsnd.c

594 lines
14 KiB
C

/////////////////////////////////////////////////////////////////////
//
// 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 <stdio.h>
#include <aclapi.h>
#include <psapi.h>
#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);
}