436 lines
12 KiB
C
436 lines
12 KiB
C
#define UNICODE
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
|
|
#include <resrc1.h>
|
|
#include "internal.h"
|
|
|
|
#define WINMM_DLL TEXT("winmm.dll")
|
|
#define WAVE_GET_NUM_DEV_FN_NAME "waveOutGetNumDevs"
|
|
#define PLAY_SOUND_FN_NAME "PlaySoundW"
|
|
|
|
|
|
typedef UINT (* WAVE_NUM_DEV_FN)(VOID);
|
|
typedef BOOL (* PLAY_SOUND_FN)( IN LPCWSTR pszSound, IN HMODULE hmod, IN DWORD fdwSound);
|
|
|
|
|
|
const WCHAR *InRangeLabelKey = TEXT("AppEvents\\EventLabels\\InfraredInRange");
|
|
const WCHAR *OutOfRangeLabelKey = TEXT("AppEvents\\EventLabels\\InfraredOutOfRange");
|
|
const WCHAR *InterruptLabelKey = TEXT("AppEvents\\EventLabels\\InfraredInterrupt");
|
|
const WCHAR *WirelessLinkKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink");
|
|
const WCHAR *InRangeSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredInRange");
|
|
const WCHAR *OutOfRangeSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredOutOfRange");
|
|
const WCHAR *InterruptSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredInterrupt");
|
|
const WCHAR *CurrentSoundKey = TEXT(".Current");
|
|
const WCHAR *DefaultSoundKey = TEXT(".Default");
|
|
const WCHAR *InRangeWav = TEXT("ir_begin.wav");
|
|
const WCHAR *OutOfRangeWav = TEXT("ir_end.wav");
|
|
const WCHAR *InterruptWav = TEXT("ir_inter.wav");
|
|
const WCHAR *SystemInfoKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
|
|
const WCHAR *SystemRootVal = TEXT("SystemRoot");
|
|
const WCHAR *MediaPath = TEXT("\\Media\\");
|
|
|
|
|
|
TCHAR gSystemRoot[64];
|
|
TCHAR InRangeWavPath[128];
|
|
TCHAR OutOfRangeWavPath[128];
|
|
TCHAR InterruptWavPath[128];
|
|
|
|
HKEY ghInRangeKey = 0;
|
|
HKEY ghOutOfRangeKey = 0;
|
|
HKEY ghInterruptKey = 0;
|
|
|
|
|
|
WAVE_NUM_DEV_FN WaveNumDev;
|
|
PLAY_SOUND_FN PlaySoundF;
|
|
|
|
|
|
BOOL
|
|
InitializeSound(
|
|
HKEY CurrentUserKey,
|
|
HANDLE Event
|
|
)
|
|
|
|
{
|
|
|
|
if (CurrentUserKey)
|
|
{
|
|
|
|
CreateRegSoundData();
|
|
|
|
// Open the wave file keys so we can monitor them for changes
|
|
|
|
RegOpenKeyEx(CurrentUserKey, InRangeSoundKey, 0, KEY_READ, &ghInRangeKey);
|
|
RegOpenKeyEx(CurrentUserKey, OutOfRangeSoundKey, 0, KEY_READ, &ghOutOfRangeKey);
|
|
RegOpenKeyEx(CurrentUserKey, InterruptSoundKey, 0, KEY_READ, &ghInterruptKey);
|
|
|
|
GetRegSoundData(Event);
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
UninitializeSound(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
if (ghInRangeKey)
|
|
{
|
|
RegCloseKey(ghInRangeKey);
|
|
ghInRangeKey = 0;
|
|
}
|
|
|
|
if (ghInterruptKey)
|
|
{
|
|
RegCloseKey(ghInterruptKey);
|
|
ghInterruptKey = 0;
|
|
}
|
|
|
|
if (ghOutOfRangeKey)
|
|
{
|
|
RegCloseKey(ghOutOfRangeKey);
|
|
ghOutOfRangeKey = 0;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
LoadSoundApis()
|
|
{
|
|
HMODULE hWinMm;
|
|
|
|
// Load multimedia module and get wave player entry points
|
|
|
|
if ((hWinMm = LoadLibrary(WINMM_DLL)) == NULL)
|
|
{
|
|
DEBUGMSG(("IRMON: failed to load winmm.dll\n")) ;
|
|
}
|
|
else
|
|
{
|
|
if (!(WaveNumDev = (WAVE_NUM_DEV_FN) GetProcAddress(hWinMm,
|
|
WAVE_GET_NUM_DEV_FN_NAME)))
|
|
{
|
|
DEBUGMSG(("IRMON: GetProcAddress failed on WaveGetNumDevs\n"));
|
|
}
|
|
|
|
if (!(PlaySoundF = (PLAY_SOUND_FN) GetProcAddress(hWinMm,
|
|
PLAY_SOUND_FN_NAME)))
|
|
{
|
|
DEBUGMSG(("IRMON: GetProcAddress failed on PlaySound\n"));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CreateRegSoundEventLabel(
|
|
const WCHAR *LabelKey,
|
|
DWORD LabelId)
|
|
{
|
|
TCHAR LabelStr[64];
|
|
|
|
// Load the localizable string label for the sound event
|
|
|
|
if (!LoadString(ghInstance, LabelId, LabelStr, sizeof(LabelStr)/sizeof(TCHAR)))
|
|
{
|
|
DEBUGMSG(("IRMON: LoadString failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
if (RegSetValue(ghCurrentUserKey, LabelKey, REG_SZ, LabelStr,
|
|
lstrlen(LabelStr)))
|
|
{
|
|
DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CreateRegSoundScheme(
|
|
TCHAR *SystemRoot,
|
|
const WCHAR *SoundKey,
|
|
const WCHAR *WavFile)
|
|
{
|
|
HKEY hSoundKey;
|
|
DWORD Disposition;
|
|
TCHAR WavPath[128];
|
|
|
|
|
|
if (RegCreateKeyEx(ghCurrentUserKey,
|
|
SoundKey,
|
|
0, // reserved MBZ
|
|
0, // class name
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
0, // security attributes
|
|
&hSoundKey,
|
|
&Disposition))
|
|
{
|
|
DEBUGMSG(("IRMON: RegCreateKey failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
if (Disposition == REG_CREATED_NEW_KEY)
|
|
{
|
|
|
|
if (RegSetValue(hSoundKey, CurrentSoundKey, REG_SZ, WavFile,
|
|
lstrlen(WavFile)))
|
|
{
|
|
DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
|
|
}
|
|
|
|
lstrcpy(WavPath, SystemRoot);
|
|
lstrcat(WavPath, MediaPath);
|
|
lstrcat(WavPath, WavFile);
|
|
|
|
if (RegSetValue(hSoundKey, DefaultSoundKey, REG_SZ, WavPath,
|
|
lstrlen(WavPath)))
|
|
{
|
|
DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hSoundKey);
|
|
}
|
|
|
|
VOID
|
|
CreateRegSoundData()
|
|
{
|
|
DWORD ValType;
|
|
HKEY hKey, hUserKey;
|
|
LONG Len;
|
|
TCHAR WirelessLinkStr[64];
|
|
|
|
// Get the system root so we can add default registry values
|
|
// i.e. Schemes\WirelessLink\InfraredInRange\.Default = "C:\winnt\media\irin.wav"
|
|
// ^^^^^^^^
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SystemInfoKey, 0, KEY_READ, &hKey))
|
|
{
|
|
DEBUGMSG(("IRMON: RegOpenKey2 failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
Len = sizeof(gSystemRoot);
|
|
|
|
if (RegQueryValueEx(hKey, SystemRootVal, 0, &ValType,
|
|
(LPBYTE) gSystemRoot, &Len))
|
|
{
|
|
DEBUGMSG(("IRMON: RegQueryValue failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
// Create the sound EventLabels and schemes if they don't exist
|
|
|
|
CreateRegSoundEventLabel(InRangeLabelKey, IDS_INRANGE_LABEL);
|
|
CreateRegSoundEventLabel(OutOfRangeLabelKey, IDS_OUTOFRANGE_LABEL);
|
|
CreateRegSoundEventLabel(InterruptLabelKey, IDS_INTERRUPT_LABEL);
|
|
|
|
if (!LoadString(ghInstance, IDS_WIRELESSLINK, WirelessLinkStr, sizeof(WirelessLinkStr)/sizeof(TCHAR)))
|
|
{
|
|
DEBUGMSG(("IRMON: LoadString failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
if (RegSetValue(ghCurrentUserKey, WirelessLinkKey, REG_SZ, WirelessLinkStr,
|
|
lstrlen(WirelessLinkStr)))
|
|
{
|
|
DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
|
|
}
|
|
|
|
CreateRegSoundScheme(gSystemRoot, InRangeSoundKey, InRangeWav);
|
|
CreateRegSoundScheme(gSystemRoot, OutOfRangeSoundKey, OutOfRangeWav);
|
|
CreateRegSoundScheme(gSystemRoot, InterruptSoundKey, InterruptWav);
|
|
|
|
}
|
|
|
|
VOID
|
|
GetRegSoundWavPath(
|
|
const WCHAR *SoundKey,
|
|
TCHAR *SoundWavPath,
|
|
LONG PathLen)
|
|
{
|
|
TCHAR CurrRegPath[128];
|
|
DWORD ValType;
|
|
HKEY hSoundKey;
|
|
int i;
|
|
BOOLEAN FullPath = FALSE;
|
|
|
|
lstrcpy(CurrRegPath, SoundKey);
|
|
lstrcat(CurrRegPath, TEXT("\\"));
|
|
lstrcat(CurrRegPath, CurrentSoundKey);
|
|
|
|
if (RegOpenKeyEx(ghCurrentUserKey, CurrRegPath, 0, KEY_READ, &hSoundKey))
|
|
{
|
|
DEBUGMSG(("IRMON: RegOpenKey3 failed %d\n", GetLastError()));
|
|
return;
|
|
}
|
|
|
|
if (RegQueryValueEx(hSoundKey, NULL, 0, &ValType,
|
|
(LPBYTE) SoundWavPath, &PathLen))
|
|
{
|
|
DEBUGMSG(("IRMON: RegQueryValue failed %d\n", GetLastError()));
|
|
RegCloseKey(hSoundKey);
|
|
return;
|
|
}
|
|
|
|
|
|
// the PlaySound API does not look in \winnt\media for
|
|
// wav files when a filename is specified, so if this is not a full
|
|
// pathname then we'll need to add "c:\winnt\media" to the WavPath.
|
|
// I'm counting on a path without '\' as an indication that it is relative.
|
|
|
|
for (i = 0; i < lstrlen(SoundWavPath); i++)
|
|
{
|
|
if (SoundWavPath[i] == TEXT('\\'))
|
|
{
|
|
FullPath = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FullPath && lstrlen(SoundWavPath) != 0)
|
|
{
|
|
TCHAR TempStr[64];
|
|
|
|
lstrcpy(TempStr, SoundWavPath);
|
|
lstrcpy(SoundWavPath, gSystemRoot);
|
|
lstrcat(SoundWavPath, MediaPath);
|
|
lstrcat(SoundWavPath, TempStr);
|
|
}
|
|
|
|
RegCloseKey(hSoundKey);
|
|
}
|
|
|
|
VOID
|
|
GetRegSoundData(
|
|
HANDLE Event
|
|
)
|
|
{
|
|
GetRegSoundWavPath(InRangeSoundKey, InRangeWavPath, sizeof(InRangeWavPath));
|
|
|
|
// DEBUGMSG(("IRMON: In range wav: %ws\n", InRangeWavPath));
|
|
|
|
GetRegSoundWavPath(OutOfRangeSoundKey, OutOfRangeWavPath, sizeof(OutOfRangeWavPath));
|
|
|
|
// DEBUGMSG(("IRMON: Out of range wav: %ws\n", OutOfRangeWavPath));
|
|
|
|
GetRegSoundWavPath(InterruptSoundKey, InterruptWavPath, sizeof(InterruptWavPath));
|
|
|
|
// DEBUGMSG(("IRMON: Interrupt wav: %ws\n", InterruptWavPath));
|
|
|
|
RegNotifyChangeKeyValue(ghInRangeKey,
|
|
TRUE, // watch child keys
|
|
REG_NOTIFY_CHANGE_LAST_SET,
|
|
Event,
|
|
TRUE); // async
|
|
|
|
RegNotifyChangeKeyValue(ghOutOfRangeKey,
|
|
TRUE, // watch child keys
|
|
REG_NOTIFY_CHANGE_LAST_SET,
|
|
Event,
|
|
TRUE); // async
|
|
|
|
RegNotifyChangeKeyValue(ghInterruptKey,
|
|
TRUE, // watch child keys
|
|
REG_NOTIFY_CHANGE_LAST_SET,
|
|
Event,
|
|
TRUE); // async
|
|
|
|
}
|
|
|
|
VOID
|
|
PlayIrSound(IRSOUND_EVENT SoundEvent)
|
|
{
|
|
int Beep1, Beep2, Beep3;
|
|
BOOL SoundPlayed = FALSE;
|
|
LPWSTR WaveSound;
|
|
DWORD Flags = 0;
|
|
|
|
|
|
if (!WaveNumDev)
|
|
{
|
|
LoadSoundApis();
|
|
}
|
|
|
|
switch (SoundEvent)
|
|
{
|
|
case INRANGE_SOUND:
|
|
WaveSound = InRangeWavPath;
|
|
|
|
Beep1 = 200;
|
|
Beep2 = 250;
|
|
Beep3 = 300;
|
|
break;
|
|
|
|
case OUTOFRANGE_SOUND:
|
|
WaveSound = OutOfRangeWavPath;
|
|
Beep1 = 300;
|
|
Beep2 = 250;
|
|
Beep3 = 200;
|
|
break;
|
|
|
|
case INTERRUPTED_SOUND:
|
|
WaveSound = InterruptWavPath;
|
|
Flags = SND_LOOP;
|
|
Beep1 = 500;
|
|
Beep2 = 350;
|
|
Beep3 = 500;
|
|
break;
|
|
|
|
case END_INTERRUPTED_SOUND:
|
|
WaveSound = NULL;
|
|
SoundPlayed = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (SoundEvent != END_INTERRUPTED_SOUND && lstrlen(WaveSound) == 0) {
|
|
//
|
|
// the path of sound file is a null string, can't play anything
|
|
//
|
|
SoundPlayed = TRUE;
|
|
|
|
} else if (WaveNumDev && PlaySoundF && WaveNumDev() > 0) {
|
|
//
|
|
// the functions are availible and there is at least on wave device
|
|
//
|
|
SoundPlayed = PlaySoundF(
|
|
WaveSound,
|
|
(HMODULE) NULL,
|
|
SND_FILENAME | SND_ASYNC | Flags
|
|
);
|
|
|
|
if (WaveSound == NULL) {
|
|
//
|
|
// we just wanted to stop the wave, set this to true so it will not try to beep
|
|
//
|
|
SoundPlayed=TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (!SoundPlayed) {
|
|
//
|
|
// could not play a wave, just uses beeps
|
|
//
|
|
DEBUGMSG(("Not Wave enabled\n"));
|
|
|
|
Beep(Beep1, 100);
|
|
Beep(Beep2, 100);
|
|
Beep(Beep3, 100);
|
|
}
|
|
}
|