/*========================================================================== * * Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved. * * File: w95hack.c * Content: Win95 hack-o-rama code * This is a HACK to handle the fact that Win95 doesn't notify * a DLL when a process is destroyed. * History: * Date By Reason * ==== == ====== * 28-mar-95 craige initial implementation * 01-apr-95 craige happy fun joy updated header file * 06-apr-95 craige reworked for new ddhelp * 09-may-95 craige loading any DLL * 16-sep-95 craige bug 1117: must UnmapViewOfFile before closing handle * 29-nov-95 angusm added HelperCreateDSFocusThread * 18-jul-96 andyco added Helper(Add/)DeleteDPlayServer * 12-oct-96 colinmc added new service to get DDHELP to get its own handle * for communicating with the DirectSound VXD * 22-jan-97 kipo return an HRESULT from HelperAddDPlayServer() * 29-jan-97 colinmc vxd handling stuff is no longer win16 lock specific * ***************************************************************************/ #undef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #include #include #include #include "w95help.h" #include "dpf.h" #undef E_FAIL #define E_FAIL 0x80004005L //extern DWORD * pdwHelperPid; //extern HANDLE * phModule; // must be defined extern DWORD dwHelperPid; extern HINSTANCE hModule; // must be defined /* * sendRequest * * communicate a request to DDHELP */ static BOOL sendRequest( LPDDHELPDATA req_phd ) { LPDDHELPDATA phd; HANDLE hmem; HANDLE hmutex; HANDLE hackevent; HANDLE hstartevent; BOOL rc; /* * get events start/ack events */ hstartevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_EVENT_NAME ); if( hstartevent == NULL ) { return FALSE; } hackevent = CreateEvent( NULL, FALSE, FALSE, DDHELP_ACK_EVENT_NAME ); if( hackevent == NULL ) { CloseHandle( hstartevent ); return FALSE; } /* * create shared memory area */ hmem = CreateFileMapping( (HANDLE) 0xffffffff, NULL, PAGE_READWRITE, 0, sizeof( DDHELPDATA ), DDHELP_SHARED_NAME ); if( hmem == NULL ) { DPF( 1, "Could not create file mapping!" ); CloseHandle( hstartevent ); CloseHandle( hackevent ); return FALSE; } phd = (LPDDHELPDATA) MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if( phd == NULL ) { DPF( 1, "Could not create view of file!" ); CloseHandle( hmem ); CloseHandle( hstartevent ); CloseHandle( hackevent ); return FALSE; } /* * wait for access to the shared memory */ hmutex = OpenMutex( SYNCHRONIZE, FALSE, DDHELP_MUTEX_NAME ); if( hmutex == NULL ) { DPF( 1, "Could not create mutex!" ); UnmapViewOfFile( phd ); CloseHandle( hmem ); CloseHandle( hstartevent ); CloseHandle( hackevent ); return FALSE; } WaitForSingleObject( hmutex, INFINITE ); /* * wake up DDHELP with our request */ memcpy( phd, req_phd, sizeof( DDHELPDATA ) ); phd->req_id = hModule; if( SetEvent( hstartevent ) ) { WaitForSingleObject( hackevent, INFINITE ); memcpy( req_phd, phd, sizeof( DDHELPDATA ) ); rc = TRUE; } else { DPF( 1, "Could not signal event to notify DDHELP" ); rc = FALSE; } /* * done with things */ ReleaseMutex( hmutex ); CloseHandle( hmutex ); CloseHandle( hstartevent ); CloseHandle( hackevent ); UnmapViewOfFile( phd ); CloseHandle( hmem ); return rc; } /* sendRequest */ /* * DoneWithHelperProcess */ void DoneWithHelperProcess( void ) { DDHELPDATA hd; if( dwHelperPid == 0 ) { return; } hd.req = DDHELPREQ_FREEDCLIST; sendRequest( &hd ); } /* DoneWithHelperProcess */ /* * WaitForHelperStartup */ BOOL WaitForHelperStartup( void ) { HANDLE hevent; DWORD rc; hevent = CreateEvent( NULL, TRUE, FALSE, DDHELP_STARTUP_EVENT_NAME ); if( hevent == NULL ) { return FALSE; } DPF( 3, "Wait DDHELP startup event to be triggered" ); rc = WaitForSingleObject( hevent, 100000 ); // fail if this doesn't work within 100 seconds CloseHandle( hevent ); if( rc == WAIT_TIMEOUT ) { return FALSE; } return TRUE; } /* WaitForHelperStartup */ /* * HelperLoadDLL * * get the helper to load a DLL for us. */ DWORD HelperLoadDLL( LPSTR dllname, LPSTR fnname, DWORD context ) { DDHELPDATA hd; DWORD rc = 0; if( dllname != NULL ) { hd.req = DDHELPREQ_LOADDLL; lstrcpy( hd.fname, dllname ); if( fnname != NULL ) { strcpy( hd.func, fnname ); hd.context = context; DPF( 3, "Context=%08lx", context ); } else { hd.func[0] = 0; } DPF( 3, "Asking DDHELP to load DLL %s", dllname ); sendRequest( &hd ); rc = (DWORD)hd.dwReturn; } return rc; } /* HelperLoadDLL */ /* * HelperCreateThread */ void HelperCreateThread( void ) { DDHELPDATA hd; hd.req = DDHELPREQ_CREATEHELPERTHREAD; sendRequest( &hd ); } /* HelperCreateThread */ /* * SignalNewProcess * * Signal DDHELP that a new process has arrived. This is called with the * DLL lock taken, so global vars are safe */ void SignalNewProcess( DWORD pid, LPHELPNOTIFYPROC proc ) { DDHELPDATA hd; if( pid == dwHelperPid ) { DPF( 3, "Helper connected to DLL - no signal required" ); return; } DPF( 3, "Signalling DDHELP that a new process has connected" ); hd.req = DDHELPREQ_NEWPID; hd.pid = pid; hd.lpNotify = proc; sendRequest( &hd ); } /* SignalNewProcess */ /* * StopWatchProcess * * Signal DDHELP to stop watching a process. This is called with the * DLL lock taken, so global vars are safe */ void StopWatchProcess( DWORD pid, LPHELPNOTIFYPROC proc ) { DDHELPDATA hd; if( pid == dwHelperPid ) { DPF( 3, "Helper connected to DLL - no signal required" ); return; } DPF( 3, "Signalling DDHELP to stop watching a process" ); hd.req = DDHELPREQ_STOPWATCHPID; hd.pid = pid; hd.lpNotify = proc; sendRequest( &hd ); } /* SignalNewProcess */ /* * SignalNewDriver * * Signal DDHELP that a new driver has been loaded. This is called with the * DLL lock taken, so global vars are safe */ void SignalNewDriver( LPSTR fname, BOOL isdisp ) { DDHELPDATA hd; DPF( 3, "Signalling DDHELP to create a new DC" ); hd.req = DDHELPREQ_NEWDC; hd.isdisp = isdisp; lstrcpy( hd.fname, fname ); sendRequest( &hd ); } /* SignalNewDriver */ /* * CreateHelperProcess */ BOOL CreateHelperProcess( LPDWORD ppid ) { if( dwHelperPid == 0 ) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE h; h = OpenEvent( SYNCHRONIZE, FALSE, DDHELP_STARTUP_EVENT_NAME ); if( h == NULL ) { si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.dwFlags = 0; si.cbReserved2 = 0; si.lpReserved2 = NULL; DPF( 3, "Creating helper process now" ); if( !CreateProcess(NULL, "ddhelp.exe", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi) ) { DPF( 2, "Could not create DDHELP.EXE" ); return FALSE; } dwHelperPid = pi.dwProcessId; DPF( 3, "Helper rocess created" ); } else { DDHELPDATA hd; DPF( 3, "DDHELP already exists, waiting for DDHELP event" ); WaitForSingleObject( h, INFINITE ); CloseHandle( h ); DPF( 3, "Asking for DDHELP pid" ); hd.req = DDHELPREQ_RETURNHELPERPID; sendRequest( &hd ); dwHelperPid = hd.pid; DPF( 3, "DDHELP pid = %08lx", dwHelperPid ); } *ppid = dwHelperPid; return TRUE; } *ppid = dwHelperPid; return FALSE; } /* CreateHelperProcess */ #ifndef WINNT //this is Just For Now... dsound will get the help it needs..jeffno 951206 /* * HelperWaveOpen * * get the helper to load a DLL for us. */ DWORD HelperWaveOpen( LPVOID lphwo, DWORD dwDeviceID, LPVOID pwfx ) { DDHELPDATA hd; if( (lphwo != NULL) && (pwfx != NULL) ) { hd.req = DDHELPREQ_WAVEOPEN; hd.pData1 = lphwo; hd.dwData1 = dwDeviceID; hd.dwData2 = (DWORD)pwfx; DPF( 3, "Asking DDHELP to Open Wave Device %d", dwDeviceID ); sendRequest( &hd ); return hd.dwReturn; } else { DPF( 3, "Helper Wave Open param error"); return MMSYSERR_ERROR; } } /* HelperWaveOpen */ /* * HelperWaveClose * * get the helper to load a DLL for us. */ DWORD HelperWaveClose( DWORD hwo ) { DDHELPDATA hd; if( (hwo != 0) ) { hd.req = DDHELPREQ_WAVECLOSE; hd.dwData1 = hwo; DPF( 3, "Asking DDHELP to Close Wave Device "); sendRequest( &hd ); return hd.dwReturn; } else { DPF( 3, "Helper Wave Close param error"); return MMSYSERR_ERROR; } } /* HelperWaveClose */ /* * HelperCreateTimer * * get the helper to load a DLL for us. */ DWORD HelperCreateTimer( DWORD dwResolution, LPVOID pTimerProc, DWORD dwInstanceData ) { DDHELPDATA hd; if( (dwResolution != 0) && (pTimerProc != NULL) ) { hd.req = DDHELPREQ_CREATETIMER; hd.pData1 = pTimerProc; hd.dwData1 = dwResolution; hd.dwData2 = dwInstanceData; DPF( 3, "Asking DDHELP to Create Timer" ); sendRequest( &hd ); return hd.dwReturn; } else { DPF( 3, "Helper Wave Close param error"); return MMSYSERR_ERROR; } } /* HelperCreateTimer */ /* * HelperKillTimer * * get the helper to load a DLL for us. */ DWORD HelperKillTimer( DWORD dwTimerID ) { DDHELPDATA hd; if( (dwTimerID != 0) ) { hd.req = DDHELPREQ_KILLTIMER; hd.dwData1 = dwTimerID; DPF( 3, "Asking DDHELP to KILL Timer %X", dwTimerID ); sendRequest( &hd ); return hd.dwReturn; } else { DPF( 3, "Helper Wave Close param error"); return MMSYSERR_ERROR; } } /* HelperKillTimer */ /* * HelperCreateDSMixerThread * * get the helper to create a mixer thread. */ HANDLE HelperCreateDSMixerThread( LPTHREAD_START_ROUTINE pfnThreadFunc, LPDWORD pdwThreadParam, DWORD dwFlags, LPDWORD pThreadId ) { DDHELPDATA hd; hd.req = DDHELPREQ_CREATEDSMIXERTHREAD; hd.pData1 = pfnThreadFunc; hd.dwData1 = (DWORD)pdwThreadParam; hd.dwData2 = dwFlags; hd.pData2 = pThreadId; sendRequest( &hd ); return (HANDLE)hd.dwReturn; } /* HelperCreateDSMixerThread /* * HelperCreateDSFocusThread * * get the helper to create a sound focus thread. */ HANDLE HelperCreateDSFocusThread( LPTHREAD_START_ROUTINE pfnThreadFunc, LPDWORD pdwThreadParam, DWORD dwFlags, LPDWORD pThreadId ) { DDHELPDATA hd; hd.req = DDHELPREQ_CREATEDSFOCUSTHREAD; hd.pData1 = pfnThreadFunc; hd.dwData1 = (DWORD)pdwThreadParam; hd.dwData2 = dwFlags; hd.pData2 = pThreadId; sendRequest( &hd ); return (HANDLE)hd.dwReturn; } /* HelperCreateDSFocusThread /* * HelperCallDSEmulatorCleanup * * Call the DirectSound function which cleans up MMSYSTEM handles */ void HelperCallDSEmulatorCleanup( LPVOID callback, LPVOID pDirectSound ) { DDHELPDATA hd; hd.req = DDHELPREQ_CALLDSCLEANUP; hd.pData1 = callback; hd.pData2 = pDirectSound; sendRequest( &hd ); } #endif //not winnt -just for now-jeffno /* * HelperCreateModeSetThread * * get the helper to load a DLL for us. */ BOOL HelperCreateModeSetThread( LPVOID callback, HANDLE *ph, LPVOID lpdd, DWORD hInstance ) { DDHELPDATA hd; HANDLE h; char str[64]; hd.req = DDHELPREQ_CREATEMODESETTHREAD; hd.lpModeSetNotify = callback; hd.pData1 = lpdd; hd.dwData1 = hInstance; sendRequest( &hd ); wsprintf( str, DDHELP_MODESET_EVENT_NAME, hInstance ); DPF( 3, "Trying to open event \"%s\"", str ); h = OpenEvent( SYNCHRONIZE, FALSE, str ); if( h == NULL ) { DPF( 3, "Could not open modeset event!" ); *ph = NULL; return FALSE; } *ph = h; DPF( 1, "HelperCreateModeSetThread GotEvent: %08lx", h ); return TRUE; } /* HelperCreateModeSetThread */ /* * HelperKillModeSetThread * * get the helper to load a DLL for us. */ void HelperKillModeSetThread( DWORD hInstance ) { DDHELPDATA hd; hd.req = DDHELPREQ_KILLMODESETTHREAD; hd.dwData1 = hInstance; sendRequest( &hd ); } /* HelperKillModeSetThread */ #ifndef WINNT /* * HelperCreateDOSBoxThread * * get the helper to create a thread so kernel mode can notify us of DOS box * changes. */ BOOL HelperCreateDOSBoxThread( LPVOID callback, HANDLE *ph, LPVOID lpdd, DWORD hInstance ) { DDHELPDATA hd; HANDLE h; char str[64]; hd.req = DDHELPREQ_CREATEDOSBOXTHREAD; hd.lpModeSetNotify = callback; hd.pData1 = lpdd; hd.dwData1 = hInstance; sendRequest( &hd ); wsprintf( str, DDHELP_DOSBOX_EVENT_NAME, hInstance ); DPF( 3, "Trying to open event \"%s\"", str ); h = OpenEvent( SYNCHRONIZE, FALSE, str ); if( h == NULL ) { DPF( 3, "Could not open DOS box event!" ); *ph = NULL; return FALSE; } *ph = h; DPF( 1, "HelperCreateDOSBoxThread GotEvent: %08lx", h ); return TRUE; } /* HelperCreateDOSBoxThread */ /* * HelperKillDOSBoxThread * * get the helper to load a DLL for us. */ void HelperKillDOSBoxThread( DWORD hInstance ) { DDHELPDATA hd; hd.req = DDHELPREQ_KILLDOSBOXTHREAD; hd.dwData1 = hInstance; sendRequest( &hd ); } /* HelperKillDOSBoxThread */ #endif //!winnt // notify dphelp.c that we have a new server on this system DWORD HelperAddDPlayServer(DWORD port) { DDHELPDATA hd; DWORD pid = GetCurrentProcessId(); memset(&hd, 0, sizeof(DDHELPDATA)); hd.req = DDHELPREQ_DPLAYADDSERVER; hd.pid = pid; hd. dwData1 = port; if (sendRequest(&hd)) return (DWORD)hd.dwReturn; else return ((DWORD) E_FAIL); } // HelperAddDPlayServer // server is going away BOOL HelperDeleteDPlayServer(void) { DDHELPDATA hd; DWORD pid = GetCurrentProcessId(); hd.req = DDHELPREQ_DPLAYDELETESERVER; hd.pid = pid; return sendRequest(&hd); } // HelperDeleteDPlayServer #ifdef WIN95 /* * Get DDHELP to load the DirectSound VXD (if it has not * already done so) and return a handle to the VXD) */ HANDLE HelperGetDSVxd( void ) { DDHELPDATA hd; hd.req = DDHELPREQ_GETDSVXDHANDLE; sendRequest( &hd ); return (HANDLE) hd.dwReturn; } /* HelperGetDSVxd */ /* * Get DDHELP to load the DirectDraw VXD (if it has not * already done so) and return a handle to the VXD) */ HANDLE HelperGetDDVxd( void ) { DDHELPDATA hd; hd.req = DDHELPREQ_GETDDVXDHANDLE; sendRequest( &hd ); return (HANDLE) hd.dwReturn; } /* HelperGetDDVxd */ #endif /* WIN95 */ /* * HelperSetOnDisplayChangeNotify * * get the helper to call us back if there is DisplayChange * message. (This is for multi-mon topology changes.) */ void HelperSetOnDisplayChangeNotify( void *pfn ) { DDHELPDATA hd; hd.req = DDHELPREQ_NOTIFYONDISPLAYCHANGE; hd.dwData1 = (DWORD_PTR)pfn; sendRequest( &hd ); return; } HINSTANCE HelperLoadLibrary(LPCSTR pszLibraryName) { DDHELPDATA hd; hd.req = DDHELPREQ_LOADLIBRARY; hd.dwData1 = (DWORD_PTR)pszLibraryName; sendRequest(&hd); return (HINSTANCE)hd.dwReturn; } BOOL HelperFreeLibrary(HINSTANCE hInst) { DDHELPDATA hd; hd.req = DDHELPREQ_FREELIBRARY; hd.dwData1 = (DWORD_PTR)hInst; sendRequest(&hd); return (BOOL)hd.dwReturn; } void HelperAddDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify) { DDHELPDATA hd; hd.req = DDHELPREQ_ADDDEVICECHANGENOTIFY; hd.pData1 = lpNotify; sendRequest(&hd); } void HelperDelDeviceChangeNotify(LPDEVICECHANGENOTIFYPROC lpNotify) { DDHELPDATA hd; hd.req = DDHELPREQ_DELDEVICECHANGENOTIFY; hd.pData1 = lpNotify; sendRequest(&hd); }