Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
12 KiB

  1. #define UNICODE
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <windows.h>
  8. #include <mmsystem.h>
  9. #include <resrc1.h>
  10. #include "internal.h"
  11. #define WINMM_DLL TEXT("winmm.dll")
  12. #define WAVE_GET_NUM_DEV_FN_NAME "waveOutGetNumDevs"
  13. #define PLAY_SOUND_FN_NAME "PlaySoundW"
  14. typedef UINT (* WAVE_NUM_DEV_FN)(VOID);
  15. typedef BOOL (* PLAY_SOUND_FN)( IN LPCWSTR pszSound, IN HMODULE hmod, IN DWORD fdwSound);
  16. const WCHAR *InRangeLabelKey = TEXT("AppEvents\\EventLabels\\InfraredInRange");
  17. const WCHAR *OutOfRangeLabelKey = TEXT("AppEvents\\EventLabels\\InfraredOutOfRange");
  18. const WCHAR *InterruptLabelKey = TEXT("AppEvents\\EventLabels\\InfraredInterrupt");
  19. const WCHAR *WirelessLinkKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink");
  20. const WCHAR *InRangeSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredInRange");
  21. const WCHAR *OutOfRangeSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredOutOfRange");
  22. const WCHAR *InterruptSoundKey = TEXT("AppEvents\\Schemes\\Apps\\WirelessLink\\InfraredInterrupt");
  23. const WCHAR *CurrentSoundKey = TEXT(".Current");
  24. const WCHAR *DefaultSoundKey = TEXT(".Default");
  25. const WCHAR *InRangeWav = TEXT("ir_begin.wav");
  26. const WCHAR *OutOfRangeWav = TEXT("ir_end.wav");
  27. const WCHAR *InterruptWav = TEXT("ir_inter.wav");
  28. const WCHAR *SystemInfoKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
  29. const WCHAR *SystemRootVal = TEXT("SystemRoot");
  30. const WCHAR *MediaPath = TEXT("\\Media\\");
  31. TCHAR gSystemRoot[64];
  32. TCHAR InRangeWavPath[128];
  33. TCHAR OutOfRangeWavPath[128];
  34. TCHAR InterruptWavPath[128];
  35. HKEY ghInRangeKey = 0;
  36. HKEY ghOutOfRangeKey = 0;
  37. HKEY ghInterruptKey = 0;
  38. WAVE_NUM_DEV_FN WaveNumDev;
  39. PLAY_SOUND_FN PlaySoundF;
  40. BOOL
  41. InitializeSound(
  42. HKEY CurrentUserKey,
  43. HANDLE Event
  44. )
  45. {
  46. if (CurrentUserKey)
  47. {
  48. CreateRegSoundData();
  49. // Open the wave file keys so we can monitor them for changes
  50. RegOpenKeyEx(CurrentUserKey, InRangeSoundKey, 0, KEY_READ, &ghInRangeKey);
  51. RegOpenKeyEx(CurrentUserKey, OutOfRangeSoundKey, 0, KEY_READ, &ghOutOfRangeKey);
  52. RegOpenKeyEx(CurrentUserKey, InterruptSoundKey, 0, KEY_READ, &ghInterruptKey);
  53. GetRegSoundData(Event);
  54. }
  55. return TRUE;
  56. }
  57. VOID
  58. UninitializeSound(
  59. VOID
  60. )
  61. {
  62. if (ghInRangeKey)
  63. {
  64. RegCloseKey(ghInRangeKey);
  65. ghInRangeKey = 0;
  66. }
  67. if (ghInterruptKey)
  68. {
  69. RegCloseKey(ghInterruptKey);
  70. ghInterruptKey = 0;
  71. }
  72. if (ghOutOfRangeKey)
  73. {
  74. RegCloseKey(ghOutOfRangeKey);
  75. ghOutOfRangeKey = 0;
  76. }
  77. return;
  78. }
  79. VOID
  80. LoadSoundApis()
  81. {
  82. HMODULE hWinMm;
  83. // Load multimedia module and get wave player entry points
  84. if ((hWinMm = LoadLibrary(WINMM_DLL)) == NULL)
  85. {
  86. DEBUGMSG(("IRMON: failed to load winmm.dll\n")) ;
  87. }
  88. else
  89. {
  90. if (!(WaveNumDev = (WAVE_NUM_DEV_FN) GetProcAddress(hWinMm,
  91. WAVE_GET_NUM_DEV_FN_NAME)))
  92. {
  93. DEBUGMSG(("IRMON: GetProcAddress failed on WaveGetNumDevs\n"));
  94. }
  95. if (!(PlaySoundF = (PLAY_SOUND_FN) GetProcAddress(hWinMm,
  96. PLAY_SOUND_FN_NAME)))
  97. {
  98. DEBUGMSG(("IRMON: GetProcAddress failed on PlaySound\n"));
  99. }
  100. }
  101. }
  102. VOID
  103. CreateRegSoundEventLabel(
  104. const WCHAR *LabelKey,
  105. DWORD LabelId)
  106. {
  107. TCHAR LabelStr[64];
  108. // Load the localizable string label for the sound event
  109. if (!LoadString(ghInstance, LabelId, LabelStr, sizeof(LabelStr)/sizeof(TCHAR)))
  110. {
  111. DEBUGMSG(("IRMON: LoadString failed %d\n", GetLastError()));
  112. return;
  113. }
  114. if (RegSetValue(ghCurrentUserKey, LabelKey, REG_SZ, LabelStr,
  115. lstrlen(LabelStr)))
  116. {
  117. DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
  118. }
  119. }
  120. VOID
  121. CreateRegSoundScheme(
  122. TCHAR *SystemRoot,
  123. const WCHAR *SoundKey,
  124. const WCHAR *WavFile)
  125. {
  126. HKEY hSoundKey;
  127. DWORD Disposition;
  128. TCHAR WavPath[128];
  129. if (RegCreateKeyEx(ghCurrentUserKey,
  130. SoundKey,
  131. 0, // reserved MBZ
  132. 0, // class name
  133. REG_OPTION_NON_VOLATILE,
  134. KEY_ALL_ACCESS,
  135. 0, // security attributes
  136. &hSoundKey,
  137. &Disposition))
  138. {
  139. DEBUGMSG(("IRMON: RegCreateKey failed %d\n", GetLastError()));
  140. return;
  141. }
  142. if (Disposition == REG_CREATED_NEW_KEY)
  143. {
  144. if (RegSetValue(hSoundKey, CurrentSoundKey, REG_SZ, WavFile,
  145. lstrlen(WavFile)))
  146. {
  147. DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
  148. }
  149. lstrcpy(WavPath, SystemRoot);
  150. lstrcat(WavPath, MediaPath);
  151. lstrcat(WavPath, WavFile);
  152. if (RegSetValue(hSoundKey, DefaultSoundKey, REG_SZ, WavPath,
  153. lstrlen(WavPath)))
  154. {
  155. DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
  156. }
  157. }
  158. RegCloseKey(hSoundKey);
  159. }
  160. VOID
  161. CreateRegSoundData()
  162. {
  163. DWORD ValType;
  164. HKEY hKey, hUserKey;
  165. LONG Len;
  166. TCHAR WirelessLinkStr[64];
  167. // Get the system root so we can add default registry values
  168. // i.e. Schemes\WirelessLink\InfraredInRange\.Default = "C:\winnt\media\irin.wav"
  169. // ^^^^^^^^
  170. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SystemInfoKey, 0, KEY_READ, &hKey))
  171. {
  172. DEBUGMSG(("IRMON: RegOpenKey2 failed %d\n", GetLastError()));
  173. return;
  174. }
  175. Len = sizeof(gSystemRoot);
  176. if (RegQueryValueEx(hKey, SystemRootVal, 0, &ValType,
  177. (LPBYTE) gSystemRoot, &Len))
  178. {
  179. DEBUGMSG(("IRMON: RegQueryValue failed %d\n", GetLastError()));
  180. return;
  181. }
  182. RegCloseKey(hKey);
  183. // Create the sound EventLabels and schemes if they don't exist
  184. CreateRegSoundEventLabel(InRangeLabelKey, IDS_INRANGE_LABEL);
  185. CreateRegSoundEventLabel(OutOfRangeLabelKey, IDS_OUTOFRANGE_LABEL);
  186. CreateRegSoundEventLabel(InterruptLabelKey, IDS_INTERRUPT_LABEL);
  187. if (!LoadString(ghInstance, IDS_WIRELESSLINK, WirelessLinkStr, sizeof(WirelessLinkStr)/sizeof(TCHAR)))
  188. {
  189. DEBUGMSG(("IRMON: LoadString failed %d\n", GetLastError()));
  190. return;
  191. }
  192. if (RegSetValue(ghCurrentUserKey, WirelessLinkKey, REG_SZ, WirelessLinkStr,
  193. lstrlen(WirelessLinkStr)))
  194. {
  195. DEBUGMSG(("IRMON: RegSetValue failed %d\n", GetLastError()));
  196. }
  197. CreateRegSoundScheme(gSystemRoot, InRangeSoundKey, InRangeWav);
  198. CreateRegSoundScheme(gSystemRoot, OutOfRangeSoundKey, OutOfRangeWav);
  199. CreateRegSoundScheme(gSystemRoot, InterruptSoundKey, InterruptWav);
  200. }
  201. VOID
  202. GetRegSoundWavPath(
  203. const WCHAR *SoundKey,
  204. TCHAR *SoundWavPath,
  205. LONG PathLen)
  206. {
  207. TCHAR CurrRegPath[128];
  208. DWORD ValType;
  209. HKEY hSoundKey;
  210. int i;
  211. BOOLEAN FullPath = FALSE;
  212. lstrcpy(CurrRegPath, SoundKey);
  213. lstrcat(CurrRegPath, TEXT("\\"));
  214. lstrcat(CurrRegPath, CurrentSoundKey);
  215. if (RegOpenKeyEx(ghCurrentUserKey, CurrRegPath, 0, KEY_READ, &hSoundKey))
  216. {
  217. DEBUGMSG(("IRMON: RegOpenKey3 failed %d\n", GetLastError()));
  218. return;
  219. }
  220. if (RegQueryValueEx(hSoundKey, NULL, 0, &ValType,
  221. (LPBYTE) SoundWavPath, &PathLen))
  222. {
  223. DEBUGMSG(("IRMON: RegQueryValue failed %d\n", GetLastError()));
  224. RegCloseKey(hSoundKey);
  225. return;
  226. }
  227. // the PlaySound API does not look in \winnt\media for
  228. // wav files when a filename is specified, so if this is not a full
  229. // pathname then we'll need to add "c:\winnt\media" to the WavPath.
  230. // I'm counting on a path without '\' as an indication that it is relative.
  231. for (i = 0; i < lstrlen(SoundWavPath); i++)
  232. {
  233. if (SoundWavPath[i] == TEXT('\\'))
  234. {
  235. FullPath = TRUE;
  236. break;
  237. }
  238. }
  239. if (!FullPath && lstrlen(SoundWavPath) != 0)
  240. {
  241. TCHAR TempStr[64];
  242. lstrcpy(TempStr, SoundWavPath);
  243. lstrcpy(SoundWavPath, gSystemRoot);
  244. lstrcat(SoundWavPath, MediaPath);
  245. lstrcat(SoundWavPath, TempStr);
  246. }
  247. RegCloseKey(hSoundKey);
  248. }
  249. VOID
  250. GetRegSoundData(
  251. HANDLE Event
  252. )
  253. {
  254. GetRegSoundWavPath(InRangeSoundKey, InRangeWavPath, sizeof(InRangeWavPath));
  255. // DEBUGMSG(("IRMON: In range wav: %ws\n", InRangeWavPath));
  256. GetRegSoundWavPath(OutOfRangeSoundKey, OutOfRangeWavPath, sizeof(OutOfRangeWavPath));
  257. // DEBUGMSG(("IRMON: Out of range wav: %ws\n", OutOfRangeWavPath));
  258. GetRegSoundWavPath(InterruptSoundKey, InterruptWavPath, sizeof(InterruptWavPath));
  259. // DEBUGMSG(("IRMON: Interrupt wav: %ws\n", InterruptWavPath));
  260. RegNotifyChangeKeyValue(ghInRangeKey,
  261. TRUE, // watch child keys
  262. REG_NOTIFY_CHANGE_LAST_SET,
  263. Event,
  264. TRUE); // async
  265. RegNotifyChangeKeyValue(ghOutOfRangeKey,
  266. TRUE, // watch child keys
  267. REG_NOTIFY_CHANGE_LAST_SET,
  268. Event,
  269. TRUE); // async
  270. RegNotifyChangeKeyValue(ghInterruptKey,
  271. TRUE, // watch child keys
  272. REG_NOTIFY_CHANGE_LAST_SET,
  273. Event,
  274. TRUE); // async
  275. }
  276. VOID
  277. PlayIrSound(IRSOUND_EVENT SoundEvent)
  278. {
  279. int Beep1, Beep2, Beep3;
  280. BOOL SoundPlayed = FALSE;
  281. LPWSTR WaveSound;
  282. DWORD Flags = 0;
  283. if (!WaveNumDev)
  284. {
  285. LoadSoundApis();
  286. }
  287. switch (SoundEvent)
  288. {
  289. case INRANGE_SOUND:
  290. WaveSound = InRangeWavPath;
  291. Beep1 = 200;
  292. Beep2 = 250;
  293. Beep3 = 300;
  294. break;
  295. case OUTOFRANGE_SOUND:
  296. WaveSound = OutOfRangeWavPath;
  297. Beep1 = 300;
  298. Beep2 = 250;
  299. Beep3 = 200;
  300. break;
  301. case INTERRUPTED_SOUND:
  302. WaveSound = InterruptWavPath;
  303. Flags = SND_LOOP;
  304. Beep1 = 500;
  305. Beep2 = 350;
  306. Beep3 = 500;
  307. break;
  308. case END_INTERRUPTED_SOUND:
  309. WaveSound = NULL;
  310. SoundPlayed = TRUE;
  311. break;
  312. }
  313. if (SoundEvent != END_INTERRUPTED_SOUND && lstrlen(WaveSound) == 0) {
  314. //
  315. // the path of sound file is a null string, can't play anything
  316. //
  317. SoundPlayed = TRUE;
  318. } else if (WaveNumDev && PlaySoundF && WaveNumDev() > 0) {
  319. //
  320. // the functions are availible and there is at least on wave device
  321. //
  322. SoundPlayed = PlaySoundF(
  323. WaveSound,
  324. (HMODULE) NULL,
  325. SND_FILENAME | SND_ASYNC | Flags
  326. );
  327. if (WaveSound == NULL) {
  328. //
  329. // we just wanted to stop the wave, set this to true so it will not try to beep
  330. //
  331. SoundPlayed=TRUE;
  332. }
  333. }
  334. if (!SoundPlayed) {
  335. //
  336. // could not play a wave, just uses beeps
  337. //
  338. DEBUGMSG(("Not Wave enabled\n"));
  339. Beep(Beep1, 100);
  340. Beep(Beep2, 100);
  341. Beep(Beep3, 100);
  342. }
  343. }