Leaked source code of windows server 2003
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.

3000 lines
82 KiB

  1. /*****************************************************************************
  2. *
  3. * Component: sndvol32.exe
  4. * File: volume.c
  5. * Purpose: main application module
  6. *
  7. * Copyright (c) 1985-1999 Microsoft Corporation
  8. *
  9. *****************************************************************************/
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include <mmsystem.h>
  13. #include <commctrl.h>
  14. #include <shellapi.h>
  15. #include <dbt.h>
  16. #include <htmlhelp.h>
  17. #include <regstr.h>
  18. #include "vu.h"
  19. #include "dlg.h"
  20. #include "volids.h"
  21. #include "volumei.h"
  22. #include "utils.h"
  23. #include "stdlib.h"
  24. #include "helpids.h"
  25. #if(WINVER >= 0x040A)
  26. //Support for new WM_DEVICECHANGE behaviour in NT5
  27. /////////////////////////////////////////////////
  28. #include <objbase.h>
  29. #include <setupapi.h>
  30. #include <cfgmgr32.h>
  31. #include <initguid.h>
  32. #include <devguid.h>
  33. #include <mmddkp.h>
  34. #include <ks.h>
  35. #include <ksmedia.h>
  36. #include <wchar.h>
  37. #define STRSAFE_LIB
  38. #include <strsafe.h>
  39. #define HMIXER_INDEX(i) ((HMIXER)IntToPtr(i))
  40. HDEVNOTIFY DeviceEventContext = NULL;
  41. BOOL bUseHandle = FALSE; //Indicates whether a handle is being used for device notification,
  42. //instead of the general KSCATEGORY_AUDIO
  43. //////////////////////////////////////////////////////
  44. //////////////////////////////////////////////////////
  45. #endif /* WINVER >= 0x040A */
  46. void Volume_SetControl(PMIXUIDIALOG pmxud, HWND hctl, int iLine, int iCtl);
  47. void Volume_GetControl(PMIXUIDIALOG pmxud, HWND hctl, int iLine, int iCtl);
  48. DWORD Volume_DialogBox(PMIXUIDIALOG pmxud);
  49. void Volume_Cleanup(PMIXUIDIALOG pmxud);
  50. void Volume_InitLine(PMIXUIDIALOG pmxud, DWORD iLine);
  51. HRESULT GetDestLineID(int mxid, DWORD *piDest);
  52. HRESULT GetSrcLineID(int mxid, DWORD *piDest);
  53. HRESULT GetDestination(DWORD mxid, int *piDest);
  54. HICON GetAppIcon (HINSTANCE hInst, UINT uiMixID);
  55. void FreeAppIcon ();
  56. HKEY OpenDeviceRegKey (UINT uiMixID, REGSAM sam);
  57. PTCHAR GetInterfaceName (DWORD dwMixerID);
  58. HKEY OpenDeviceBrandRegKey (UINT uiMixID);
  59. /* string declarations */
  60. const TCHAR gszParentClass[] = TEXT( "SNDVOL32" );
  61. const TCHAR gszAppClassName[] = TEXT( "Volume Control" );
  62. const TCHAR gszTrayClassName[] = TEXT( "Tray Volume" );
  63. #ifdef DEBUG
  64. static void _dlout(LPSTR szExp, LPSTR szFile, UINT uLine)
  65. {
  66. char sz[256];
  67. StringCchPrintfA(sz, SIZEOF(sz), "%s, file %s, line %u\r\n", szExp, szFile, uLine);
  68. OutputDebugStringA(sz);
  69. }
  70. #define dlout(exp) (void)(_dlout(exp, __FILE__, __LINE__), 0)
  71. #else
  72. #define dlout(exp) ((void)0)
  73. #endif
  74. /* app global
  75. * */
  76. TCHAR gszHelpFileName[MAX_PATH];
  77. TCHAR gszHtmlHelpFileName[MAX_PATH];
  78. BOOL gfIsRTL;
  79. BOOL fCanDismissWindow = FALSE;
  80. BOOL gfRecord = FALSE;
  81. HICON ghiconApp = NULL;
  82. static HHOOK fpfnOldMsgFilter;
  83. static HOOKPROC fpfnMsgHook;
  84. //Data used for supporting context menu help
  85. BOOL bF1InMenu=FALSE; //If true F1 was pressed on a menu item.
  86. UINT currMenuItem=0; //The current selected menu item if any.
  87. static HWND ghwndApp=NULL;
  88. /*
  89. * Number of uniquely supported devices.
  90. *
  91. * */
  92. int Volume_NumDevs()
  93. {
  94. int cNumDevs = 0;
  95. #pragma message("----Nonmixer issue here.")
  96. // cNumDevs = Nonmixer_GetNumDevs();
  97. cNumDevs += Mixer_GetNumDevs();
  98. return cNumDevs;
  99. }
  100. /*
  101. * Volume_EndDialog
  102. *
  103. * */
  104. void Volume_EndDialog(
  105. PMIXUIDIALOG pmxud,
  106. DWORD dwErr,
  107. MMRESULT mmr)
  108. {
  109. pmxud->dwReturn = dwErr;
  110. if (dwErr == MIXUI_MMSYSERR)
  111. pmxud->mmr = mmr;
  112. if (IsWindow(pmxud->hwnd))
  113. PostMessage(pmxud->hwnd, WM_CLOSE, 0, 0);
  114. }
  115. /*
  116. * Volume_OnMenuCommand
  117. *
  118. * */
  119. BOOL Volume_OnMenuCommand(
  120. HWND hwnd,
  121. int id,
  122. HWND hctl,
  123. UINT unotify)
  124. {
  125. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  126. switch(id)
  127. {
  128. case IDM_PROPERTIES:
  129. if (Properties(pmxud, hwnd))
  130. {
  131. Volume_GetSetStyle(&pmxud->dwStyle, SET);
  132. Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
  133. }
  134. break;
  135. case IDM_HELPTOPICS:
  136. SendMessage(pmxud->hParent, MYWM_HELPTOPICS, 0, 0L);
  137. break;
  138. case IDM_HELPABOUT:
  139. {
  140. TCHAR ach[256];
  141. GetWindowText(hwnd, ach, SIZEOF(ach));
  142. ShellAbout(hwnd
  143. , ach
  144. , NULL
  145. , (HICON)SendMessage(hwnd, WM_QUERYDRAGICON, 0, 0L));
  146. break;
  147. }
  148. case IDM_ADVANCED:
  149. {
  150. HMENU hmenu;
  151. pmxud->dwStyle ^= MXUD_STYLEF_ADVANCED;
  152. hmenu = GetMenu(hwnd);
  153. if (hmenu)
  154. {
  155. CheckMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND
  156. | ((pmxud->dwStyle & MXUD_STYLEF_ADVANCED)?MF_CHECKED:MF_UNCHECKED));
  157. }
  158. Volume_GetSetStyle(&pmxud->dwStyle, SET);
  159. Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
  160. break;
  161. }
  162. case IDM_SMALLMODESWITCH:
  163. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  164. {
  165. pmxud->dwStyle ^= MXUD_STYLEF_SMALL;
  166. if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
  167. {
  168. pmxud->dwStyle &= ~MXUD_STYLEF_STATUS;
  169. }
  170. else
  171. pmxud->dwStyle |= MXUD_STYLEF_STATUS;
  172. Volume_GetSetStyle(&pmxud->dwStyle, SET);
  173. Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
  174. }
  175. break;
  176. case IDM_EXIT:
  177. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  178. return TRUE;
  179. }
  180. return FALSE;
  181. }
  182. /*
  183. * Volume_OnCommand
  184. *
  185. * - Process WM_COMMAND
  186. *
  187. * Note: We need a 2 way mapping. Dialog control -> Mixer control
  188. * and Mixer control -> Dialog control.
  189. *
  190. * */
  191. void Volume_OnCommand(
  192. HWND hdlg,
  193. int id,
  194. HWND hctl,
  195. UINT unotify)
  196. {
  197. int iMixerLine;
  198. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hdlg);
  199. //
  200. // Filter menu messages
  201. //
  202. if (Volume_OnMenuCommand(hdlg, id, hctl, unotify))
  203. return;
  204. // Each control is offset from the original template control by IDOFFSET.
  205. // e.g.
  206. // IDC_VOLUME, IDC_VOLUME+IDOFFSET, .. IDC_VOLUME+(IDOFFSET*cMixerLines)
  207. //
  208. iMixerLine = id/IDOFFSET - 1;
  209. switch ((id % IDOFFSET) + IDC_MIXERCONTROLS)
  210. {
  211. case IDC_SWITCH:
  212. Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_SWITCH);
  213. break;
  214. case IDC_ADVANCED:
  215. if (MXUD_ADVANCED(pmxud) && !(pmxud->dwStyle & MXUD_STYLEF_SMALL))
  216. Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_ADVANCED);
  217. break;
  218. case IDC_MULTICHANNEL:
  219. Volume_SetControl(pmxud, hctl, iMixerLine, MIXUI_MULTICHANNEL);
  220. break;
  221. }
  222. }
  223. /*
  224. * Volume_GetLineItem
  225. *
  226. * - Helper function.
  227. * */
  228. HWND Volume_GetLineItem(
  229. HWND hdlg,
  230. DWORD iLine,
  231. DWORD idCtrl)
  232. {
  233. HWND hwnd;
  234. DWORD id;
  235. id = (iLine * IDOFFSET) + idCtrl;
  236. hwnd = GetDlgItem(hdlg, id);
  237. return hwnd;
  238. }
  239. /* - - - - - - - - - */
  240. /*
  241. * Volume_TimeProc
  242. *
  243. * This is the callback for the periodic timer that does updates for
  244. * controls that need to be polled. We only allocate one per app to keep
  245. * the number of callbacks down.
  246. */
  247. void CALLBACK Volume_TimeProc(
  248. UINT idEvent,
  249. UINT uReserved,
  250. DWORD_PTR dwUser,
  251. DWORD_PTR dwReserved1,
  252. DWORD_PTR dwReserved2)
  253. {
  254. PMIXUIDIALOG pmxud = (PMIXUIDIALOG)dwUser;
  255. if (!(pmxud->dwFlags & MXUD_FLAGSF_USETIMER))
  256. return;
  257. if (pmxud->cTimeInQueue < 5)
  258. {
  259. pmxud->cTimeInQueue++;
  260. PostMessage(pmxud->hwnd, MYWM_TIMER, 0, 0L);
  261. }
  262. }
  263. #define PROPATOM TEXT("dingprivprop")
  264. const TCHAR gszDingPropAtom[] = PROPATOM;
  265. #define SETPROP(x,y) SetProp((x), gszDingPropAtom, (HANDLE)(y))
  266. #define GETPROP(x) (PMIXUIDIALOG)GetProp((x), gszDingPropAtom)
  267. #define REMOVEPROP(x) RemoveProp(x,gszDingPropAtom)
  268. LRESULT CALLBACK Volume_TrayVolProc(
  269. HWND hwnd,
  270. UINT umsg,
  271. WPARAM wParam,
  272. LPARAM lParam)
  273. {
  274. PMIXUIDIALOG pmxud = (PMIXUIDIALOG)GETPROP(hwnd);
  275. static const TCHAR cszDefSnd[] = TEXT(".Default");
  276. if (umsg == WM_KILLFOCUS)
  277. {
  278. //
  279. // if we've just been made inactive via keyboard, clear the signal
  280. //
  281. pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
  282. }
  283. if (umsg == WM_KEYUP && (pmxud->dwTrayInfo & MXUD_TRAYINFOF_SIGNAL))
  284. {
  285. if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_END ||
  286. wParam == VK_HOME || wParam == VK_LEFT || wParam == VK_RIGHT ||
  287. wParam == VK_PRIOR || wParam == VK_NEXT || wParam == VK_SPACE)
  288. {
  289. PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS);
  290. pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
  291. }
  292. }
  293. if (umsg == WM_LBUTTONUP && (pmxud->dwTrayInfo & MXUD_TRAYINFOF_SIGNAL))
  294. {
  295. PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS);
  296. pmxud->dwTrayInfo &= ~MXUD_TRAYINFOF_SIGNAL;
  297. }
  298. return CallWindowProc(pmxud->lpfnTrayVol, hwnd, umsg, wParam, lParam);
  299. }
  300. #if(WINVER >= 0x040A)
  301. void DeviceChange_Cleanup()
  302. {
  303. if (DeviceEventContext)
  304. {
  305. UnregisterDeviceNotification(DeviceEventContext);
  306. DeviceEventContext = 0;
  307. }
  308. bUseHandle = FALSE;
  309. return;
  310. }
  311. /*
  312. **************************************************************************************************
  313. GetDeviceHandle()
  314. given a mixerID this functions opens its corresponding device handle. This handle can be used
  315. to register for DeviceNotifications.
  316. dwMixerID -- The mixer ID
  317. phDevice -- a pointer to a handle. This pointer will hold the handle value if the function is
  318. successful
  319. return values -- If the handle could be obtained successfully the return vlaue is TRUE.
  320. **************************************************************************************************
  321. */
  322. BOOL GetDeviceHandle(DWORD dwMixerID, HANDLE *phDevice)
  323. {
  324. MMRESULT mmr;
  325. ULONG cbSize=0;
  326. TCHAR *szInterfaceName=NULL;
  327. //Query for the Device interface name
  328. mmr = mixerMessage((HMIXER)ULongToPtr(dwMixerID), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L);
  329. if(MMSYSERR_NOERROR == mmr)
  330. {
  331. szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR));
  332. if(!szInterfaceName)
  333. {
  334. return FALSE;
  335. }
  336. mmr = mixerMessage((HMIXER)ULongToPtr(dwMixerID), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize);
  337. if(MMSYSERR_NOERROR != mmr)
  338. {
  339. GlobalFreePtr(szInterfaceName);
  340. return FALSE;
  341. }
  342. }
  343. else
  344. {
  345. return FALSE;
  346. }
  347. //Get an handle on the device interface name.
  348. *phDevice = CreateFile(szInterfaceName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  349. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  350. GlobalFreePtr(szInterfaceName);
  351. if(INVALID_HANDLE_VALUE == *phDevice)
  352. {
  353. return FALSE;
  354. }
  355. return TRUE;
  356. }
  357. /* DeviceChange_Init()
  358. * First time initialization for WM_DEVICECHANGE messages
  359. *
  360. * On NT 5.0, you have to register for device notification
  361. */
  362. BOOL DeviceChange_Init(HWND hWnd, DWORD dwMixerID)
  363. {
  364. DEV_BROADCAST_HANDLE DevBrodHandle;
  365. DEV_BROADCAST_DEVICEINTERFACE dbi;
  366. HANDLE hMixerDevice;
  367. //If we had registered already for device notifications, unregister ourselves.
  368. DeviceChange_Cleanup();
  369. //If we get the device handle register for device notifications on it.
  370. if(GetDeviceHandle(dwMixerID, &hMixerDevice))
  371. {
  372. memset(&DevBrodHandle, 0, sizeof(DEV_BROADCAST_HANDLE));
  373. DevBrodHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  374. DevBrodHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
  375. DevBrodHandle.dbch_handle = hMixerDevice;
  376. DeviceEventContext = RegisterDeviceNotification(hWnd, &DevBrodHandle,
  377. DEVICE_NOTIFY_WINDOW_HANDLE);
  378. if(hMixerDevice)
  379. {
  380. CloseHandle(hMixerDevice);
  381. hMixerDevice = NULL;
  382. }
  383. if(DeviceEventContext)
  384. {
  385. bUseHandle = TRUE;
  386. return TRUE;
  387. }
  388. }
  389. if(!DeviceEventContext)
  390. {
  391. //Register for notifications from all audio devices. KSCATEGORY_AUDIO gives notifications
  392. //on device arrival and removal. We cannot identify which device the notification has arrived for
  393. //but we can take some precautionary measures on these messages so that we do not crash.
  394. dbi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  395. dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  396. dbi.dbcc_reserved = 0;
  397. dbi.dbcc_classguid = KSCATEGORY_AUDIO;
  398. dbi.dbcc_name[0] = TEXT('\0');
  399. DeviceEventContext = RegisterDeviceNotification(hWnd,
  400. (PVOID)&dbi,
  401. DEVICE_NOTIFY_WINDOW_HANDLE);
  402. if(!DeviceEventContext)
  403. return FALSE;
  404. }
  405. return TRUE;
  406. }
  407. #endif /* WINVER >= 0x040A */
  408. //fixes bug where controls are lopped off on high-contract extra-large modes
  409. void AdjustForStatusBar(PMIXUIDIALOG pmxud)
  410. {
  411. RECT statusrect, windowrect;
  412. statusrect.bottom = 0;
  413. statusrect.top = 0;
  414. if (pmxud)
  415. {
  416. if (pmxud->hStatus)
  417. {
  418. GetClientRect(pmxud->hStatus,&statusrect);
  419. GetWindowRect(pmxud->hwnd,&windowrect);
  420. if (statusrect.bottom - statusrect.top > 20)
  421. {
  422. int y_adjustment = (statusrect.bottom - statusrect.top) - 20;
  423. MoveWindow(pmxud->hwnd, windowrect.left, windowrect.top, windowrect.right - windowrect.left,
  424. (windowrect.bottom - windowrect.top) + y_adjustment, FALSE );
  425. GetClientRect(pmxud->hwnd,&windowrect);
  426. MoveWindow(pmxud->hStatus, statusrect.left, windowrect.bottom - (statusrect.bottom - statusrect.top), statusrect.right - statusrect.left,
  427. statusrect.bottom - statusrect.top, FALSE );
  428. }
  429. } //end if hStatus is valid
  430. } //end if pmxud is not null
  431. }
  432. /*
  433. *
  434. * */
  435. BOOL Volume_Init(
  436. PMIXUIDIALOG pmxud)
  437. {
  438. DWORD iLine, ictrl;
  439. RECT rc, rcWnd;
  440. if (!Mixer_Init(pmxud) && !Nonmixer_Init(pmxud))
  441. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  442. //
  443. // For all line controls, make sure we initialize the values.
  444. //
  445. for (iLine = 0; iLine < pmxud->cmxul; iLine++)
  446. {
  447. //
  448. // init the ui control
  449. //
  450. Volume_InitLine(pmxud, iLine);
  451. for (ictrl = MIXUI_FIRST; ictrl <= MIXUI_LAST; ictrl++)
  452. {
  453. PMIXUICTRL pmxc = &pmxud->amxul[iLine].acr[ictrl];
  454. //
  455. // set initial settings
  456. //
  457. if (pmxc->state == MIXUI_CONTROL_INITIALIZED)
  458. Volume_GetControl(pmxud, pmxc->hwnd, iLine, ictrl);
  459. }
  460. }
  461. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  462. {
  463. RECT rcBase;
  464. HWND hBase;
  465. RECT rcAdv,rcBorder;
  466. HWND hAdv,hBorder;
  467. DWORD i;
  468. LONG lPrev;
  469. POINT pos;
  470. HMENU hmenu;
  471. HMONITOR hMonitor;
  472. MONITORINFO monitorInfo;
  473. if (GetWindowRect(pmxud->hwnd, &rcWnd))
  474. {
  475. if (pmxud->cmxul == 1)
  476. {
  477. // Adjust size if small
  478. if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
  479. rcWnd.right -= 20;
  480. ShowWindow(GetDlgItem(pmxud->hwnd, IDC_BORDER), SW_HIDE);
  481. }
  482. if (!Volume_GetSetRegistryRect(pmxud->szMixer
  483. , pmxud->szDestination
  484. , &rc
  485. , GET))
  486. {
  487. rc.left = rcWnd.left;
  488. rc.top = rcWnd.top;
  489. }
  490. else
  491. {
  492. // Check if the rect is visible is any of the monitors
  493. if (!MonitorFromRect(&rc, MONITOR_DEFAULTTONULL))
  494. {
  495. //The window is not visible. Let's center it in the nearest monitor.
  496. //Note: the window could be in this state if (1) the display mode was changed from
  497. //a high-resolution to a lower resolution, with the mixer in the corner. Or,
  498. //(2) the multi-mon configuration was rearranged.
  499. hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
  500. if (hMonitor)
  501. {
  502. monitorInfo.cbSize = sizeof(MONITORINFO);
  503. if (GetMonitorInfo(hMonitor, &monitorInfo))
  504. {
  505. rc.left = ((monitorInfo.rcWork.right - monitorInfo.rcWork.left) - (rcWnd.right - rcWnd.left)) / 2; //center in x
  506. rc.top = ((monitorInfo.rcWork.bottom - monitorInfo.rcWork.top) - (rcWnd.bottom - rcWnd.top)) / 3; //and a little towards the top
  507. }
  508. }
  509. }
  510. //else, the window is visible, so let's leave the (x,y) as read from the settings
  511. }
  512. //
  513. // Adjusted bottom to match switch bottom
  514. //
  515. if (!(pmxud->dwStyle & MXUD_STYLEF_SMALL))
  516. {
  517. hBase = GetDlgItem(pmxud->hwnd, IDC_SWITCH);
  518. if (hBase && GetWindowRect(hBase, &rcBase))
  519. {
  520. rcWnd.bottom = rcBase.bottom;
  521. }
  522. //
  523. // Adjusted bottom to match "Advanced" bottom
  524. //
  525. if (MXUD_ADVANCED(pmxud))
  526. {
  527. hAdv = GetDlgItem(pmxud->hwnd, IDC_ADVANCED);
  528. if (hAdv && GetWindowRect(hAdv, &rcAdv))
  529. {
  530. lPrev = rcWnd.bottom;
  531. rcWnd.bottom = rcAdv.bottom;
  532. //
  533. // Adjust height of all border lines
  534. //
  535. lPrev = rcWnd.bottom - lPrev;
  536. for (i = 0; i < pmxud->cmxul; i++)
  537. {
  538. hBorder = GetDlgItem(pmxud->hwnd,
  539. IDC_BORDER+(IDOFFSET*i));
  540. if (hBorder && GetWindowRect(hBorder, &rcBorder))
  541. {
  542. MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rcBorder, 2);
  543. pos.x = rcBorder.left;
  544. pos.y = rcBorder.top;
  545. MoveWindow(hBorder
  546. , pos.x
  547. , pos.y
  548. , rcBorder.right - rcBorder.left
  549. , (rcBorder.bottom - rcBorder.top) + lPrev
  550. , TRUE );
  551. }
  552. }
  553. }
  554. }
  555. //
  556. // Allocate some more space.
  557. //
  558. rcWnd.bottom += 28;
  559. }
  560. MoveWindow(pmxud->hwnd, rc.left, rc.top, rcWnd.right - rcWnd.left,
  561. rcWnd.bottom - rcWnd.top, FALSE );
  562. //
  563. // Tack on the status bar after resizing the dialog
  564. //
  565. //init status bar hwnd variable
  566. pmxud->hStatus = NULL;
  567. if (pmxud->dwStyle & MXUD_STYLEF_STATUS)
  568. {
  569. MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rcWnd, 2);
  570. pos.x = rcWnd.left;
  571. pos.y = rcWnd.bottom;
  572. pmxud->hStatus = CreateWindowEx ( gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0
  573. , STATUSCLASSNAME
  574. , TEXT ("X")
  575. , WS_VISIBLE | WS_CHILD
  576. , 0
  577. , pos.y
  578. , rcWnd.right - rcWnd.left
  579. , 14
  580. , pmxud->hwnd
  581. , NULL
  582. , pmxud->hInstance
  583. , NULL);
  584. if (pmxud->hStatus)
  585. {
  586. SendMessage(pmxud->hStatus, WM_SETTEXT, 0,
  587. (LPARAM)(LPVOID)(LPTSTR)pmxud->szMixer);
  588. }
  589. else
  590. pmxud->dwStyle ^= MXUD_STYLEF_STATUS;
  591. }
  592. AdjustForStatusBar(pmxud);
  593. hmenu = GetMenu(pmxud->hwnd);
  594. CheckMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND
  595. | ((pmxud->dwStyle & MXUD_STYLEF_ADVANCED)?MF_CHECKED:MF_UNCHECKED));
  596. if (pmxud->dwStyle & MXUD_STYLEF_SMALL || pmxud->dwFlags & MXUD_FLAGSF_NOADVANCED)
  597. EnableMenuItem(hmenu, IDM_ADVANCED, MF_BYCOMMAND | MF_GRAYED);
  598. }
  599. if (pmxud->dwFlags & MXUD_FLAGSF_USETIMER)
  600. {
  601. pmxud->cTimeInQueue = 0;
  602. pmxud->uTimerID = timeSetEvent(100
  603. , 50
  604. , Volume_TimeProc
  605. , (DWORD_PTR)pmxud
  606. , TIME_PERIODIC);
  607. if (!pmxud->uTimerID)
  608. pmxud->dwFlags &= ~MXUD_FLAGSF_USETIMER;
  609. }
  610. }
  611. else
  612. {
  613. WNDPROC lpfnOldTrayVol;
  614. HWND hVol;
  615. hVol = pmxud->amxul[0].acr[MIXUI_VOLUME].hwnd;
  616. lpfnOldTrayVol = SubclassWindow(hVol, Volume_TrayVolProc);
  617. if (lpfnOldTrayVol)
  618. {
  619. pmxud->lpfnTrayVol = lpfnOldTrayVol;
  620. SETPROP(hVol, pmxud);
  621. }
  622. }
  623. #if(WINVER >= 0x040A)
  624. //Register for WM_DEVICECHANGE messages
  625. DeviceChange_Init(pmxud->hwnd, pmxud->mxid);
  626. #endif /* WINVER >= 0x040A */
  627. return TRUE;
  628. }
  629. /*
  630. * Volume_OnInitDialog
  631. *
  632. * - Process WM_INITDIALOG
  633. *
  634. * */
  635. BOOL Volume_OnInitDialog(
  636. HWND hwnd,
  637. HWND hwndFocus,
  638. LPARAM lParam)
  639. {
  640. PMIXUIDIALOG pmxud;
  641. RECT rc;
  642. //
  643. // set app instance data
  644. //
  645. SETMIXUIDIALOG(hwnd, lParam);
  646. pmxud = (PMIXUIDIALOG)(LPVOID)lParam;
  647. pmxud->hwnd = hwnd;
  648. if (!Volume_Init(pmxud))
  649. {
  650. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  651. }
  652. else
  653. {
  654. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  655. PostMessage(hwnd, MYWM_WAKEUP, 0, 0);
  656. }
  657. //
  658. // If we are so big that we need a scroll bar, then make one.
  659. //
  660. rc.top = rc.bottom = 0;
  661. rc.left = 60; // typical width of a dialog template
  662. rc.right = Dlg_HorizSize(pmxud->lpDialog);
  663. MapDialogRect(hwnd, &rc);
  664. pmxud->cxDlgContent = rc.right;
  665. pmxud->cxScroll = rc.left;
  666. pmxud->xOffset = 0;
  667. GetClientRect(hwnd, &rc);
  668. pmxud->xOffset = 0;
  669. pmxud->cxDlgWidth = rc.right;
  670. if (rc.right < pmxud->cxDlgContent)
  671. {
  672. RECT rcWindow;
  673. SCROLLINFO si;
  674. LONG lStyle = GetWindowStyle(hwnd);
  675. SetWindowLong(hwnd, GWL_STYLE, lStyle | WS_HSCROLL);
  676. si.cbSize = sizeof(si);
  677. si.fMask = SIF_PAGE | SIF_RANGE;
  678. si.nMin = 0;
  679. si.nMax = pmxud->cxDlgContent - 1; // endpoint is inclusive
  680. si.nPage = rc.right;
  681. SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
  682. // Grow the dialog to accomodate the scrollbar
  683. GetWindowRect(hwnd, &rcWindow);
  684. SetWindowPos(hwnd, NULL, 0, 0, rcWindow.right - rcWindow.left,
  685. rcWindow.bottom - rcWindow.top + GetSystemMetrics(SM_CYHSCROLL),
  686. SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
  687. SWP_NOOWNERZORDER | SWP_NOZORDER);
  688. }
  689. //
  690. // If we are the tray master, don't ask to set focus
  691. //
  692. return (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER));
  693. }
  694. /*
  695. * Volume_OnDestroy
  696. *
  697. * Shut down this dialog. DO NOT TOUCH the hmixer!
  698. *
  699. * */
  700. void Volume_OnDestroy(
  701. HWND hwnd)
  702. {
  703. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  704. DeviceChange_Cleanup();
  705. if (!pmxud)
  706. return;
  707. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  708. {
  709. HWND hVol;
  710. hVol = pmxud->amxul[0].acr[MIXUI_VOLUME].hwnd;
  711. SubclassWindow(hVol, pmxud->lpfnTrayVol);
  712. REMOVEPROP(hVol);
  713. }
  714. Volume_Cleanup(pmxud);
  715. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  716. {
  717. //
  718. // save window position
  719. //
  720. if (!IsIconic(hwnd))
  721. {
  722. RECT rc;
  723. GetWindowRect(hwnd, &rc);
  724. Volume_GetSetRegistryRect(pmxud->szMixer
  725. , pmxud->szDestination
  726. , &rc
  727. , SET);
  728. }
  729. }
  730. if (pmxud->dwReturn == MIXUI_RESTART)
  731. PostMessage(pmxud->hParent, MYWM_RESTART, 0, (LPARAM)pmxud);
  732. else
  733. PostMessage(pmxud->hParent, WM_CLOSE, 0, 0L);
  734. }
  735. /*
  736. * Volume_SetControl
  737. *
  738. * Update system controls from visual controls
  739. *
  740. * */
  741. void Volume_SetControl(
  742. PMIXUIDIALOG pmxud,
  743. HWND hctl,
  744. int imxul,
  745. int itype)
  746. {
  747. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  748. Mixer_SetControl(pmxud, hctl, imxul, itype);
  749. else
  750. Nonmixer_SetControl(pmxud, hctl, imxul, itype);
  751. }
  752. /*
  753. * Volume_GetControl
  754. *
  755. * Update visual controls from system controls
  756. * */
  757. void Volume_GetControl(
  758. PMIXUIDIALOG pmxud,
  759. HWND hctl,
  760. int imxul,
  761. int itype)
  762. {
  763. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  764. Mixer_GetControl(pmxud, hctl, imxul, itype);
  765. else
  766. Nonmixer_GetControl(pmxud, hctl, imxul, itype);
  767. }
  768. extern DWORD GetWaveOutID(BOOL *pfPreferred);
  769. /*
  770. * Volume_PlayDefaultSound
  771. *
  772. * Play the default sound on the current mixer
  773. *
  774. * */
  775. void Volume_PlayDefaultSound (PMIXUIDIALOG pmxud)
  776. {
  777. /*
  778. // TODO: Implement for all master volumes. Convert mixerid to wave id then
  779. // use wave API to play the file
  780. TCHAR szDefSnd[MAX_PATH];
  781. long lcb = sizeof (szDefSnd);
  782. // Get the default sound filename
  783. if (ERROR_SUCCESS != RegQueryValue (HKEY_CURRENT_USER, REGSTR_PATH_APPS_DEFAULT TEXT("\\.Default\\.Current"), szDefSnd, &lcb) ||
  784. 0 >= lstrlen (szDefSnd))
  785. return;
  786. */
  787. DWORD dwWave = GetWaveOutID (NULL);
  788. UINT uiMixID;
  789. // Check Parameter
  790. if (!pmxud)
  791. return;
  792. // Play the sound only if we are on the default mixer...
  793. if (MMSYSERR_NOERROR == mixerGetID (ULongToPtr(dwWave), &uiMixID, MIXER_OBJECTF_WAVEOUT) &&
  794. pmxud -> mxid == uiMixID)
  795. {
  796. static const TCHAR cszDefSnd[] = TEXT(".Default");
  797. PlaySound(cszDefSnd, NULL, SND_ASYNC | SND_ALIAS);
  798. }
  799. }
  800. /*
  801. * Volume_ScrollTo
  802. *
  803. * Move the scrollbar position.
  804. */
  805. void Volume_ScrollTo(
  806. PMIXUIDIALOG pmxud,
  807. int pos
  808. )
  809. {
  810. RECT rc;
  811. /*
  812. * Keep in range.
  813. */
  814. pos = max(pos, 0);
  815. pos = min(pos, pmxud->cxDlgContent - pmxud->cxDlgWidth);
  816. /*
  817. * Scroll the window contents accordingly. But don't scroll
  818. * the status bar.
  819. */
  820. GetClientRect(pmxud->hwnd, &rc);
  821. if (pmxud->hStatus)
  822. {
  823. RECT rcStatus;
  824. GetWindowRect(pmxud->hStatus, &rcStatus);
  825. MapWindowRect(NULL, pmxud->hwnd, &rcStatus);
  826. SubtractRect(&rc, &rc, &rcStatus);
  827. }
  828. rc.left = -pmxud->cxDlgContent;
  829. rc.right = pmxud->cxDlgContent;
  830. ScrollWindowEx(pmxud->hwnd, pmxud->xOffset - pos, 0,
  831. &rc, NULL, NULL, NULL,
  832. SW_ERASE | SW_INVALIDATE | SW_SCROLLCHILDREN);
  833. pmxud->xOffset = pos;
  834. /*
  835. * Move the scrollbar to match.
  836. */
  837. SetScrollPos(pmxud->hwnd, SB_HORZ, pos, TRUE);
  838. }
  839. /*
  840. * Volume_ScrollContent
  841. *
  842. * Process scroll bar messages for the dialog itself.
  843. */
  844. void Volume_ScrollContent(
  845. PMIXUIDIALOG pmxud,
  846. UINT code,
  847. int pos
  848. )
  849. {
  850. switch (code) {
  851. case SB_LINELEFT:
  852. Volume_ScrollTo(pmxud, pmxud->xOffset - pmxud->cxScroll);
  853. break;
  854. case SB_LINERIGHT:
  855. Volume_ScrollTo(pmxud, pmxud->xOffset + pmxud->cxScroll);
  856. break;
  857. case SB_PAGELEFT:
  858. Volume_ScrollTo(pmxud, pmxud->xOffset - pmxud->cxDlgWidth);
  859. break;
  860. case SB_PAGERIGHT:
  861. Volume_ScrollTo(pmxud, pmxud->xOffset + pmxud->cxDlgWidth);
  862. break;
  863. case SB_LEFT:
  864. Volume_ScrollTo(pmxud, 0);
  865. break;
  866. case SB_RIGHT:
  867. Volume_ScrollTo(pmxud, MAXLONG);
  868. break;
  869. case SB_THUMBPOSITION:
  870. case SB_THUMBTRACK:
  871. Volume_ScrollTo(pmxud, pos);
  872. break;
  873. }
  874. }
  875. /*
  876. * Volume_OnXScroll
  877. *
  878. * Process Scroll bar messages
  879. *
  880. * */
  881. void Volume_OnXScroll(
  882. HWND hwnd,
  883. HWND hwndCtl,
  884. UINT code,
  885. int pos)
  886. {
  887. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  888. UINT id;
  889. int ictl;
  890. int iline;
  891. // If this is a scroll message from the dialog itself, then we need
  892. // to scroll our content.
  893. if (hwndCtl == NULL)
  894. {
  895. Volume_ScrollContent(pmxud, code, pos);
  896. return;
  897. }
  898. id = GetDlgCtrlID(hwndCtl);
  899. iline = id/IDOFFSET - 1;
  900. ictl = ((id % IDOFFSET) + IDC_MIXERCONTROLS == IDC_BALANCE)
  901. ? MIXUI_BALANCE : MIXUI_VOLUME;
  902. Volume_SetControl(pmxud, hwndCtl, iline, ictl);
  903. //
  904. // Make sure a note gets played
  905. //
  906. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  907. pmxud->dwTrayInfo |= MXUD_TRAYINFOF_SIGNAL;
  908. // Play a sound on for the master volume or balance slider when the
  909. // user ends the scroll and we are still in focus and the topmost app.
  910. if (code == SB_ENDSCROLL && pmxud && !(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER) &&
  911. pmxud->amxul[iline].pvcd &&
  912. (MXUL_STYLEF_DESTINATION & pmxud->amxul[iline].dwStyle)
  913. && hwndCtl == GetFocus() && hwnd == GetForegroundWindow ())
  914. {
  915. Volume_PlayDefaultSound (pmxud);
  916. }
  917. }
  918. /*
  919. * Volume_OnMyTimer
  920. *
  921. * Frequent update timer for meters
  922. * */
  923. void Volume_OnMyTimer(
  924. HWND hwnd)
  925. {
  926. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  927. if (!pmxud)
  928. return;
  929. if (pmxud->cTimeInQueue > 0)
  930. pmxud->cTimeInQueue--;
  931. if (!(pmxud->dwFlags & MXUD_FLAGSF_USETIMER))
  932. return;
  933. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  934. Mixer_PollingUpdate(pmxud);
  935. else
  936. Nonmixer_PollingUpdate(pmxud);
  937. }
  938. /*
  939. * Volume_OnTimer
  940. *
  941. * Infrequent update timer for tray shutdown
  942. * */
  943. void Volume_OnTimer(
  944. HWND hwnd,
  945. UINT id)
  946. {
  947. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  948. KillTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID);
  949. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  950. }
  951. /*
  952. * Volume_OnMixmControlChange
  953. *
  954. * Handle control changes
  955. *
  956. * */
  957. void Volume_OnMixmControlChange(
  958. HWND hwnd,
  959. HMIXER hmx,
  960. DWORD dwControlID)
  961. {
  962. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  963. Mixer_GetControlFromID(pmxud, dwControlID);
  964. }
  965. /*
  966. * Volume_EnableLine
  967. *
  968. * Enable/Disable a line
  969. *
  970. * */
  971. void Volume_EnableLine(
  972. PMIXUIDIALOG pmxud,
  973. DWORD iLine,
  974. BOOL fEnable)
  975. {
  976. DWORD iCtrl;
  977. PMIXUICTRL pmxc;
  978. for (iCtrl = MIXUI_FIRST; iCtrl <= MIXUI_LAST; iCtrl++ )
  979. {
  980. pmxc = &pmxud->amxul[iLine].acr[iCtrl];
  981. if (pmxc->state == MIXUI_CONTROL_INITIALIZED)
  982. EnableWindow(pmxc->hwnd, fEnable);
  983. }
  984. pmxud->amxul[iLine].dwStyle ^= MXUL_STYLEF_DISABLED;
  985. }
  986. /*
  987. * Volume_InitLine
  988. *
  989. * Initialize the UI controls for the dialog
  990. *
  991. * */
  992. void Volume_InitLine(
  993. PMIXUIDIALOG pmxud,
  994. DWORD iLine)
  995. {
  996. HWND ctrl;
  997. PMIXUICTRL pmxc;
  998. //
  999. // Peakmeter control
  1000. //
  1001. pmxc = &pmxud->amxul[iLine].acr[MIXUI_VUMETER];
  1002. ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VUMETER);
  1003. pmxc->hwnd = ctrl;
  1004. if (! (pmxc->state == MIXUI_CONTROL_ENABLED) )
  1005. {
  1006. if (ctrl)
  1007. ShowWindow(ctrl, SW_HIDE);
  1008. }
  1009. else if (ctrl)
  1010. {
  1011. HWND hvol;
  1012. SendMessage(ctrl, VU_SETRANGEMAX, 0, VOLUME_TICS);
  1013. SendMessage(ctrl, VU_SETRANGEMIN, 0, 0);
  1014. hvol = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VOLUME);
  1015. if (hvol)
  1016. {
  1017. RECT rc;
  1018. POINT pos;
  1019. GetWindowRect(hvol, &rc);
  1020. MapWindowPoints(NULL, pmxud->hwnd, (LPPOINT)&rc, 2);
  1021. pos.x = rc.left;
  1022. pos.y = rc.top;
  1023. MoveWindow(hvol
  1024. , pos.x - 15
  1025. , pos.y
  1026. , rc.right - rc.left
  1027. , rc.bottom - rc.top
  1028. , FALSE);
  1029. }
  1030. //
  1031. // Signal use of update timer
  1032. //
  1033. pmxud->dwFlags |= MXUD_FLAGSF_USETIMER;
  1034. pmxc->state = MIXUI_CONTROL_INITIALIZED;
  1035. }
  1036. else
  1037. pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
  1038. //
  1039. // Balance control
  1040. //
  1041. pmxc = &pmxud->amxul[iLine].acr[MIXUI_BALANCE];
  1042. ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_BALANCE);
  1043. pmxc->hwnd = ctrl;
  1044. if (ctrl)
  1045. {
  1046. SendMessage(ctrl, TBM_SETRANGE, 0, MAKELONG(0, 64));
  1047. SendMessage(ctrl, TBM_SETTICFREQ, 32, 0 );
  1048. SendMessage(ctrl, TBM_SETPOS, TRUE, 32);
  1049. if (pmxc->state != MIXUI_CONTROL_ENABLED)
  1050. {
  1051. EnableWindow(ctrl, FALSE);
  1052. }
  1053. else
  1054. pmxc->state = MIXUI_CONTROL_INITIALIZED;
  1055. }
  1056. else
  1057. pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
  1058. //
  1059. // Volume control
  1060. //
  1061. pmxc = &pmxud->amxul[iLine].acr[MIXUI_VOLUME];
  1062. ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_VOLUME);
  1063. pmxc->hwnd = ctrl;
  1064. if (ctrl)
  1065. {
  1066. SendMessage(ctrl, TBM_SETRANGE, 0, MAKELONG(0, VOLUME_TICS));
  1067. SendMessage(ctrl, TBM_SETTICFREQ, (VOLUME_TICS + 5)/6, 0 );
  1068. if (pmxc->state != MIXUI_CONTROL_ENABLED)
  1069. {
  1070. SendMessage(ctrl, TBM_SETPOS, TRUE, 128);
  1071. EnableWindow(ctrl, FALSE);
  1072. }
  1073. else
  1074. pmxc->state = MIXUI_CONTROL_INITIALIZED;
  1075. }
  1076. else
  1077. pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
  1078. //
  1079. // Switch
  1080. //
  1081. pmxc = &pmxud->amxul[iLine].acr[MIXUI_SWITCH];
  1082. ctrl = Volume_GetLineItem(pmxud->hwnd, iLine, IDC_SWITCH);
  1083. pmxc->hwnd = ctrl;
  1084. if (ctrl)
  1085. {
  1086. if (pmxc->state != MIXUI_CONTROL_ENABLED)
  1087. EnableWindow(ctrl, FALSE);
  1088. else
  1089. pmxc->state = MIXUI_CONTROL_INITIALIZED;
  1090. }
  1091. else
  1092. pmxc->state = MIXUI_CONTROL_UNINITIALIZED;
  1093. }
  1094. /*
  1095. * Volume_OnMixmLineChange
  1096. *
  1097. * */
  1098. void Volume_OnMixmLineChange(
  1099. HWND hwnd,
  1100. HMIXER hmx,
  1101. DWORD dwLineID)
  1102. {
  1103. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  1104. DWORD iLine;
  1105. for (iLine = 0; iLine < pmxud->cmxul; iLine++)
  1106. {
  1107. if ( dwLineID == pmxud->amxul[iLine].pvcd->dwLineID )
  1108. {
  1109. MIXERLINE ml;
  1110. MMRESULT mmr;
  1111. BOOL fEnable;
  1112. ml.cbStruct = sizeof(ml);
  1113. ml.dwLineID = dwLineID;
  1114. mmr = mixerGetLineInfo((HMIXEROBJ)hmx, &ml, MIXER_GETLINEINFOF_LINEID);
  1115. if (mmr != MMSYSERR_NOERROR)
  1116. {
  1117. fEnable = !(ml.fdwLine & MIXERLINE_LINEF_DISCONNECTED);
  1118. Volume_EnableLine(pmxud, iLine, fEnable);
  1119. }
  1120. }
  1121. }
  1122. }
  1123. /*
  1124. * Volume_OnActivate
  1125. *
  1126. * Important for tray volume only. Dismisses the dialog and starts an
  1127. * expiration timer.
  1128. *
  1129. * */
  1130. void Volume_OnActivate(
  1131. HWND hwnd,
  1132. UINT state,
  1133. HWND hwndActDeact,
  1134. BOOL fMinimized)
  1135. {
  1136. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  1137. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  1138. {
  1139. return;
  1140. }
  1141. if (state != WA_INACTIVE)
  1142. {
  1143. fCanDismissWindow = TRUE;
  1144. }
  1145. else if (fCanDismissWindow)
  1146. {
  1147. PostMessage(hwnd, WM_CLOSE, 0, 0L);
  1148. /*
  1149. DWORD dwTimeout = 5 * 60 * 1000;
  1150. fCanDismissWindow = FALSE;
  1151. ShowWindow(hwnd, SW_HIDE);
  1152. //
  1153. // Set expiration timer. If no one adjusts the volume, make the
  1154. // application go away after 5 minutes.
  1155. //
  1156. dwTimeout = Volume_GetTrayTimeout(dwTimeout);
  1157. SetTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID, dwTimeout, NULL);
  1158. */
  1159. }
  1160. }
  1161. /*
  1162. * Volume_PropogateMessage
  1163. *
  1164. * WM_SYSCOLORCHANGE needs to be send to all child windows (esp. trackbars)
  1165. */
  1166. void Volume_PropagateMessage(
  1167. HWND hwnd,
  1168. UINT uMessage,
  1169. WPARAM wParam,
  1170. LPARAM lParam)
  1171. {
  1172. HWND hwndChild;
  1173. for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL;
  1174. hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
  1175. {
  1176. SendMessage(hwndChild, uMessage, wParam, lParam);
  1177. }
  1178. }
  1179. /*
  1180. * Volume_OnPaint
  1181. *
  1182. * Handle custom painting
  1183. * */
  1184. void Volume_OnPaint(HWND hwnd)
  1185. {
  1186. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  1187. RECT rc;
  1188. PAINTSTRUCT ps;
  1189. HDC hdc;
  1190. hdc = BeginPaint(hwnd, &ps);
  1191. //
  1192. // for all styles other than the tray master, draw an etched
  1193. // line to delinate the menu area
  1194. //
  1195. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  1196. {
  1197. GetClientRect(hwnd, &rc);
  1198. rc.bottom = 0;
  1199. DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP);
  1200. EndPaint(hwnd, &ps);
  1201. return;
  1202. }
  1203. //
  1204. // for the tray master, draw some significant icon to indicate
  1205. // volume
  1206. //
  1207. GetWindowRect(GetDlgItem(hwnd, IDC_VOLUMECUE), &rc);
  1208. MapWindowPoints(NULL, hwnd, (LPPOINT)&rc, 2);
  1209. DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_DIAGONAL|BF_TOP|BF_LEFT);
  1210. DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_TOP);
  1211. rc.bottom -= 8;
  1212. DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_RIGHT);
  1213. EndPaint(hwnd, &ps);
  1214. }
  1215. /*
  1216. * Volume_OnClose
  1217. *
  1218. * */
  1219. void Volume_OnClose(
  1220. HWND hwnd)
  1221. {
  1222. DestroyWindow(hwnd);
  1223. }
  1224. /*
  1225. * Volume_OnEndSession
  1226. *
  1227. * */
  1228. void Volume_OnEndSession(
  1229. HWND hwnd,
  1230. BOOL fEnding)
  1231. {
  1232. if (!fEnding)
  1233. return;
  1234. //
  1235. // Be sure to call the close code to free open handles
  1236. //
  1237. Volume_OnClose(hwnd);
  1238. }
  1239. #define V_DC_STATEF_PENDING 0x00000001
  1240. #define V_DC_STATEF_REMOVING 0x00000002
  1241. #define V_DC_STATEF_ARRIVING 0x00000004
  1242. /*
  1243. * Volume_OnDeviceChange
  1244. *
  1245. * */
  1246. void Volume_OnDeviceChange(
  1247. HWND hwnd,
  1248. WPARAM wParam,
  1249. LPARAM lParam)
  1250. {
  1251. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  1252. MMRESULT mmr;
  1253. UINT uMxID;
  1254. PDEV_BROADCAST_DEVICEINTERFACE bdi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  1255. PDEV_BROADCAST_HANDLE bh = (PDEV_BROADCAST_HANDLE)lParam;
  1256. //
  1257. // Determine if this is our event.
  1258. //
  1259. if(!DeviceEventContext)
  1260. return;
  1261. //If we have an handle on the device then we get a DEV_BROADCAST_HDR structure as the lParam.
  1262. //Or else it means that we have registered for the general audio category KSCATEGORY_AUDIO.
  1263. if(bUseHandle)
  1264. {
  1265. if(!bh ||
  1266. bh->dbch_devicetype != DBT_DEVTYP_HANDLE)
  1267. {
  1268. return;
  1269. }
  1270. }
  1271. else if (!bdi ||
  1272. bdi->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE ||
  1273. !IsEqualGUID(&KSCATEGORY_AUDIO, &bdi->dbcc_classguid) ||
  1274. !(*bdi->dbcc_name)
  1275. )
  1276. {
  1277. return;
  1278. }
  1279. switch (wParam)
  1280. {
  1281. case DBT_DEVICEQUERYREMOVE:
  1282. //The mixer has to be shutdown now.
  1283. //Posting a WM_CLOSE message as Volume_EndDialog does will not help.
  1284. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  1285. Mixer_Shutdown(pmxud);
  1286. else
  1287. Nonmixer_Shutdown(pmxud);
  1288. // Don't attempt restart, just exit. The wavemapper is not
  1289. // updated with the new default device, so do not know what
  1290. // to restart as and we should NOT hardcode device #0!
  1291. // pmxud->mxid = (DWORD) 0;
  1292. // GetDestination(pmxud->mxid, &pmxud->iDest);
  1293. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  1294. return;
  1295. case DBT_DEVICEQUERYREMOVEFAILED: // The query failed, the device will not be removed, so lets reopen it.
  1296. mmr = Volume_GetDefaultMixerID(&uMxID, gfRecord);
  1297. pmxud->mxid = (mmr == MMSYSERR_NOERROR)?uMxID:0;
  1298. GetDestination(pmxud->mxid, &pmxud->iDest);
  1299. Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
  1300. return;
  1301. case DBT_DEVNODES_CHANGED:
  1302. //
  1303. // We cannot reliably determine the final state of the devices in
  1304. // the system until this message is broadcast.
  1305. //
  1306. if (pmxud->dwDeviceState & V_DC_STATEF_PENDING)
  1307. {
  1308. pmxud->dwDeviceState ^= V_DC_STATEF_PENDING;
  1309. break;
  1310. }
  1311. return;
  1312. case DBT_DEVICEREMOVECOMPLETE:
  1313. //The mixer has to be shutdown now.
  1314. //Posting a WM_CLOSE message as Volume_EndDialog does will not help.
  1315. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  1316. Mixer_Shutdown(pmxud);
  1317. else
  1318. Nonmixer_Shutdown(pmxud);
  1319. //A DBT_DEVICEQUERYREMOVE is not guaranteed before a DBT_DEVICEREMOVECOMPLETE.
  1320. //There should be a check here to see if this message is meant for this device.
  1321. //We do not know a way of doing that right now.
  1322. // Don't attempt restart, just exit. The wavemapper is not
  1323. // updated with the new default device, so do not know what
  1324. // to restart as and we should NOT hardcode device #0!
  1325. // pmxud->mxid = (DWORD) 0;
  1326. // GetDestination(pmxud->mxid, &pmxud->iDest);
  1327. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  1328. pmxud->dwDeviceState = V_DC_STATEF_PENDING
  1329. | V_DC_STATEF_REMOVING;
  1330. return;
  1331. case DBT_DEVICEARRIVAL:
  1332. //
  1333. // A devnode is being added to the system
  1334. //
  1335. pmxud->dwDeviceState = V_DC_STATEF_PENDING
  1336. | V_DC_STATEF_ARRIVING;
  1337. return;
  1338. default:
  1339. return;
  1340. }
  1341. mmr = Volume_GetDefaultMixerID(&uMxID, gfRecord);
  1342. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  1343. {
  1344. if ( mmr == MMSYSERR_NOERROR
  1345. && (pmxud->dwDeviceState & V_DC_STATEF_ARRIVING))
  1346. {
  1347. DWORD dwDevNode;
  1348. if (!mixerMessage((HMIXER)UIntToPtr(uMxID), DRV_QUERYDEVNODE
  1349. , (DWORD_PTR)&dwDevNode, 0L))
  1350. {
  1351. if (dwDevNode == pmxud->dwDevNode)
  1352. {
  1353. //
  1354. // ignore this device, it doesn't affect us
  1355. //
  1356. pmxud->dwDeviceState = 0L;
  1357. return;
  1358. }
  1359. }
  1360. }
  1361. //
  1362. // Our device state has changed. Just go away.
  1363. //
  1364. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  1365. }
  1366. else if (pmxud->dwDeviceState & V_DC_STATEF_REMOVING)
  1367. {
  1368. //
  1369. // Restart with the default mixer if we can.
  1370. //
  1371. pmxud->mxid = (mmr == MMSYSERR_NOERROR)?uMxID:0;
  1372. GetDestination(pmxud->mxid, &pmxud->iDest);
  1373. Volume_EndDialog(pmxud, MIXUI_RESTART, 0);
  1374. }
  1375. pmxud->dwDeviceState = 0L;
  1376. }
  1377. void Volume_OnWakeup(
  1378. HWND hwnd,
  1379. WPARAM wParam)
  1380. {
  1381. POINT pos;
  1382. RECT rc, rcPopup;
  1383. LONG w,h;
  1384. HWND hTrack;
  1385. HMONITOR hMonitor;
  1386. MONITORINFO moninfo;
  1387. PMIXUIDIALOG pmxud = GETMIXUIDIALOG(hwnd);
  1388. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  1389. return;
  1390. KillTimer(hwnd, VOLUME_TRAYSHUTDOWN_ID);
  1391. if (wParam != 0)
  1392. {
  1393. Volume_EndDialog(pmxud, MIXUI_EXIT, 0);
  1394. return;
  1395. }
  1396. //
  1397. // Make the tray volume come up.
  1398. //
  1399. //Get the current position.
  1400. GetCursorPos(&pos);
  1401. //Get the width and height of the popup.
  1402. GetWindowRect(hwnd, &rc);
  1403. w = rc.right - rc.left; //This value will always be positive as left is always lesser than right.
  1404. h = rc.bottom - rc.top; //This value will always be positive as top is always lesser than bottom.
  1405. //Initialize the rectangle for the popup. Position it so that the popup appears to the right,
  1406. //bottom of the cursor.
  1407. rcPopup.left = pos.x;
  1408. rcPopup.right = pos.x + w;
  1409. rcPopup.top = pos.y;
  1410. rcPopup.bottom = pos.y+h;
  1411. //Get the rectangle for the monitor.
  1412. hMonitor = MonitorFromPoint(pos, MONITOR_DEFAULTTONEAREST);
  1413. moninfo.cbSize = sizeof(moninfo);
  1414. GetMonitorInfo(hMonitor,&moninfo);
  1415. //If the popup rectangle is leaking off from the right of the screen. Make it appear on the
  1416. //left of the cursor.
  1417. if(rcPopup.right > moninfo.rcWork.right)
  1418. {
  1419. OffsetRect(&rcPopup, -w, 0);
  1420. }
  1421. //If the popup rectangle is leaking off from the bottom of the screen. Make it appear on top
  1422. //of the cursor.
  1423. if(rcPopup.bottom > moninfo.rcWork.bottom)
  1424. {
  1425. OffsetRect(&rcPopup, 0, -h);
  1426. }
  1427. SetWindowPos(hwnd
  1428. , HWND_TOPMOST
  1429. , rcPopup.left
  1430. , rcPopup.top
  1431. , w
  1432. , h
  1433. , SWP_SHOWWINDOW);
  1434. // make us come to the front
  1435. SetForegroundWindow(hwnd);
  1436. fCanDismissWindow = TRUE;
  1437. hTrack = GetDlgItem(hwnd, IDC_VOLUME);
  1438. if (hTrack)
  1439. SetFocus(hTrack);
  1440. }
  1441. /*
  1442. * VolumeProc
  1443. *
  1444. * */
  1445. INT_PTR CALLBACK VolumeProc(
  1446. HWND hdlg,
  1447. UINT msg,
  1448. WPARAM wparam,
  1449. LPARAM lparam)
  1450. {
  1451. switch (msg)
  1452. {
  1453. case WM_INITDIALOG:
  1454. return HANDLE_WM_INITDIALOG(hdlg, wparam, lparam, Volume_OnInitDialog);
  1455. case WM_COMMAND:
  1456. HANDLE_WM_COMMAND(hdlg, wparam, lparam, Volume_OnCommand);
  1457. break;
  1458. case WM_CLOSE:
  1459. HANDLE_WM_CLOSE(hdlg, wparam, lparam, Volume_OnClose);
  1460. break;
  1461. case WM_DESTROY:
  1462. HANDLE_WM_DESTROY(hdlg, wparam, lparam, Volume_OnDestroy);
  1463. break;
  1464. case WM_HSCROLL:
  1465. case WM_VSCROLL:
  1466. //
  1467. // balance and volume are essentially the same
  1468. //
  1469. HANDLE_WM_XSCROLL(hdlg, wparam, lparam, Volume_OnXScroll);
  1470. break;
  1471. case WM_MENUSELECT:
  1472. //Keep track of which menu bar item is currently popped up.
  1473. //This will be used for displaying the appropriate help from the mplayer.hlp file
  1474. //when the user presses the F1 key.
  1475. currMenuItem = (UINT)LOWORD(wparam);
  1476. break;
  1477. case MM_MIXM_LINE_CHANGE:
  1478. HANDLE_MM_MIXM_LINE_CHANGE(hdlg
  1479. , wparam
  1480. , lparam
  1481. , Volume_OnMixmLineChange);
  1482. return FALSE;
  1483. case MM_MIXM_CONTROL_CHANGE:
  1484. HANDLE_MM_MIXM_CONTROL_CHANGE(hdlg
  1485. , wparam
  1486. , lparam
  1487. , Volume_OnMixmControlChange);
  1488. return FALSE;
  1489. case WM_ACTIVATE:
  1490. HANDLE_WM_ACTIVATE(hdlg, wparam, lparam, Volume_OnActivate);
  1491. break;
  1492. case MYWM_TIMER:
  1493. HANDLE_MYWM_TIMER(hdlg, wparam, lparam, Volume_OnMyTimer);
  1494. break;
  1495. case WM_TIMER:
  1496. HANDLE_WM_TIMER(hdlg, wparam, lparam, Volume_OnTimer);
  1497. break;
  1498. case WM_PAINT:
  1499. HANDLE_WM_PAINT(hdlg, wparam, lparam, Volume_OnPaint);
  1500. break;
  1501. case WM_SYSCOLORCHANGE:
  1502. Volume_PropagateMessage(hdlg, msg, wparam, lparam);
  1503. break;
  1504. case WM_DEVICECHANGE:
  1505. HANDLE_WM_IDEVICECHANGE(hdlg, wparam, lparam, Volume_OnDeviceChange);
  1506. break;
  1507. case MYWM_WAKEUP:
  1508. HANDLE_MYWM_WAKEUP(hdlg, wparam, lparam, Volume_OnWakeup);
  1509. break;
  1510. case WM_ENDSESSION:
  1511. HANDLE_WM_ENDSESSION(hdlg, wparam, lparam, Volume_OnEndSession);
  1512. break;
  1513. default:
  1514. break;
  1515. }
  1516. return FALSE;
  1517. }
  1518. /*
  1519. * Volume_AddLine
  1520. *
  1521. * */
  1522. BOOL Volume_AddLine(
  1523. PMIXUIDIALOG pmxud,
  1524. LPBYTE lpAdd,
  1525. DWORD cbAdd,
  1526. DWORD dwStyle,
  1527. PVOLCTRLDESC pvcd)
  1528. {
  1529. LPBYTE pbNew;
  1530. DWORD cbNew;
  1531. PMIXUILINE pmxul;
  1532. if (pmxud->amxul)
  1533. {
  1534. pmxul = (PMIXUILINE)GlobalReAllocPtr(pmxud->amxul
  1535. , (pmxud->cmxul+1)*sizeof(MIXUILINE)
  1536. , GHND);
  1537. }
  1538. else
  1539. {
  1540. pmxul = (PMIXUILINE)GlobalAllocPtr(GHND, sizeof(MIXUILINE));
  1541. }
  1542. if (!pmxul)
  1543. return FALSE;
  1544. pbNew = Dlg_HorizAttach(pmxud->lpDialog
  1545. , pmxud->cbDialog
  1546. , lpAdd
  1547. , cbAdd
  1548. , (WORD)(IDOFFSET * pmxud->cmxul)
  1549. , &cbNew );
  1550. if (!pbNew)
  1551. {
  1552. if (!pmxud->amxul)
  1553. GlobalFreePtr(pmxul);
  1554. return FALSE;
  1555. }
  1556. pmxul[pmxud->cmxul].dwStyle = dwStyle;
  1557. pmxul[pmxud->cmxul].pvcd = pvcd;
  1558. pmxud->amxul = pmxul;
  1559. pmxud->lpDialog = pbNew;
  1560. pmxud->cbDialog = cbNew;
  1561. pmxud->cmxul ++;
  1562. return TRUE;
  1563. }
  1564. /*
  1565. * Volume_Cleanup
  1566. *
  1567. * */
  1568. void Volume_Cleanup(
  1569. PMIXUIDIALOG pmxud)
  1570. {
  1571. if (pmxud->dwFlags & MXUD_FLAGSF_USETIMER)
  1572. {
  1573. timeKillEvent(pmxud->uTimerID);
  1574. pmxud->dwFlags ^= MXUD_FLAGSF_USETIMER;
  1575. }
  1576. if (pmxud->dwFlags & MXUD_FLAGSF_BADDRIVER)
  1577. {
  1578. pmxud->dwFlags ^= MXUD_FLAGSF_BADDRIVER;
  1579. }
  1580. if (pmxud->dwFlags & MXUD_FLAGSF_NOADVANCED)
  1581. {
  1582. pmxud->dwFlags ^= MXUD_FLAGSF_NOADVANCED;
  1583. }
  1584. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  1585. Mixer_Shutdown(pmxud);
  1586. else
  1587. Nonmixer_Shutdown(pmxud);
  1588. if (pmxud->lpDialog)
  1589. GlobalFreePtr(pmxud->lpDialog);
  1590. if (pmxud->amxul)
  1591. GlobalFreePtr(pmxud->amxul);
  1592. if (pmxud->avcd)
  1593. GlobalFreePtr(pmxud->avcd);
  1594. pmxud->amxul = NULL;
  1595. pmxud->lpDialog = NULL;
  1596. pmxud->cbDialog = 0;
  1597. pmxud->cmxul = 0;
  1598. pmxud->hwnd = NULL;
  1599. pmxud->hStatus = NULL;
  1600. pmxud->uTimerID = 0;
  1601. pmxud->dwDevNode = 0L;
  1602. FreeAppIcon ();
  1603. }
  1604. /*
  1605. * Volume_CreateVolume
  1606. * */
  1607. BOOL Volume_CreateVolume(
  1608. PMIXUIDIALOG pmxud)
  1609. {
  1610. WNDCLASS wc;
  1611. LPBYTE lpDst = NULL, lpSrc = NULL, lpMaster = NULL;
  1612. DWORD cbDst, cbSrc, cbMaster;
  1613. PVOLCTRLDESC avcd;
  1614. DWORD cvcd;
  1615. DWORD ivcd;
  1616. DWORD imxul;
  1617. DWORD dwSupport = 0L;
  1618. BOOL fAddLine = TRUE;
  1619. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  1620. wc.hIcon = GetAppIcon (pmxud->hInstance, pmxud->mxid);
  1621. wc.lpszMenuName = NULL;
  1622. wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  1623. wc.hInstance = pmxud->hInstance;
  1624. wc.style = CS_HREDRAW | CS_VREDRAW;
  1625. wc.lpfnWndProc = DefDlgProc;
  1626. wc.cbClsExtra = 0;
  1627. wc.cbWndExtra = DLGWINDOWEXTRA;
  1628. wc.lpszClassName = (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  1629. ? gszTrayClassName : gszAppClassName;
  1630. RegisterClass(&wc);
  1631. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  1632. {
  1633. lpMaster = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
  1634. , MAKEINTRESOURCE(IDD_TRAYMASTER)
  1635. , &cbMaster);
  1636. if (!lpMaster)
  1637. return FALSE;
  1638. }
  1639. else
  1640. {
  1641. if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
  1642. {
  1643. lpDst = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
  1644. , MAKEINTRESOURCE(IDD_SMDST)
  1645. , &cbDst);
  1646. lpSrc = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
  1647. , MAKEINTRESOURCE(IDD_SMSRC)
  1648. , &cbSrc);
  1649. }
  1650. else
  1651. {
  1652. lpDst = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
  1653. , MAKEINTRESOURCE(IDD_DESTINATION)
  1654. , &cbDst);
  1655. lpSrc = (LPBYTE)Dlg_LoadResource(pmxud->hInstance
  1656. , MAKEINTRESOURCE(IDD_SOURCE)
  1657. , &cbSrc);
  1658. }
  1659. if (!lpDst || !lpSrc)
  1660. return FALSE;
  1661. }
  1662. pmxud->lpDialog = NULL;
  1663. pmxud->cbDialog = 0;
  1664. pmxud->amxul = NULL;
  1665. pmxud->cmxul = 0;
  1666. pmxud->avcd = NULL;
  1667. pmxud->cvcd = 0;
  1668. //
  1669. // Create the volume description
  1670. //
  1671. if (pmxud->dwFlags & MXUD_FLAGSF_MIXER)
  1672. {
  1673. HMIXER hmx;
  1674. MMRESULT mmr;
  1675. //
  1676. // Mixer API's work much more efficiently with a mixer handle...
  1677. //
  1678. mmr = mixerOpen(&hmx, pmxud->mxid, 0L, 0L, MIXER_OBJECTF_MIXER);
  1679. if(MMSYSERR_NOERROR == mmr)
  1680. {
  1681. avcd = Mixer_CreateVolumeDescription((HMIXEROBJ)hmx
  1682. , pmxud->iDest
  1683. , &cvcd);
  1684. mixerClose(hmx);
  1685. }
  1686. else
  1687. {
  1688. avcd = Mixer_CreateVolumeDescription((HMIXEROBJ)ULongToPtr(pmxud->mxid)
  1689. , pmxud->iDest
  1690. , &cvcd);
  1691. }
  1692. if (!Mixer_GetDeviceName(pmxud))
  1693. {
  1694. GlobalFreePtr(avcd);
  1695. avcd = NULL;
  1696. }
  1697. }
  1698. else
  1699. {
  1700. avcd = Nonmixer_CreateVolumeDescription(pmxud->iDest
  1701. , &cvcd);
  1702. if (!Nonmixer_GetDeviceName(pmxud))
  1703. {
  1704. GlobalFreePtr(avcd);
  1705. avcd = NULL;
  1706. }
  1707. }
  1708. //
  1709. // Create the dialog box to go along with it
  1710. //
  1711. if (avcd)
  1712. {
  1713. pmxud->avcd = avcd;
  1714. pmxud->cvcd = cvcd;
  1715. if (pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER)
  1716. {
  1717. if (!Volume_AddLine(pmxud
  1718. , lpMaster
  1719. , cbMaster
  1720. , MXUL_STYLEF_DESTINATION
  1721. , &avcd[0]))
  1722. {
  1723. return FALSE;
  1724. }
  1725. }
  1726. else
  1727. {
  1728. BOOL fFirstRun;
  1729. //
  1730. // Restore HIDDEN flags.
  1731. //
  1732. // On first run, be sure to re-save state so there's something
  1733. // there.
  1734. //
  1735. fFirstRun = !Volume_GetSetRegistryLineStates(pmxud->szMixer
  1736. , pmxud->avcd[0].szShortName
  1737. , avcd
  1738. , cvcd
  1739. , GET);
  1740. for (ivcd = 0; ivcd < cvcd; ivcd++)
  1741. {
  1742. //
  1743. // Lines are marked hidden if a state has been saved in the
  1744. // registry or no state has been saved and there are too many
  1745. // unnecessary lines.
  1746. //
  1747. if (avcd[ivcd].dwSupport & VCD_SUPPORTF_HIDDEN)
  1748. {
  1749. continue;
  1750. }
  1751. //
  1752. // Lines are marked VISIBLE if they have sufficient controls
  1753. // to be useful.
  1754. //
  1755. if (!(avcd[ivcd].dwSupport & VCD_SUPPORTF_VISIBLE))
  1756. {
  1757. continue;
  1758. }
  1759. //
  1760. // Show only defaults on first run.
  1761. //
  1762. if (fFirstRun && !(avcd[ivcd].dwSupport & VCD_SUPPORTF_DEFAULT))
  1763. {
  1764. avcd[ivcd].dwSupport |= VCD_SUPPORTF_HIDDEN;
  1765. continue;
  1766. }
  1767. //
  1768. // For those lines that have important controls, add them to
  1769. // the UI.
  1770. //
  1771. if ((pmxud->dwFlags & MXUD_FLAGSF_MIXER) && ivcd == 0 )
  1772. fAddLine = Volume_AddLine(pmxud
  1773. , lpDst
  1774. , cbDst
  1775. , MXUL_STYLEF_DESTINATION
  1776. , &avcd[ivcd]);
  1777. else
  1778. fAddLine = Volume_AddLine(pmxud
  1779. , lpSrc
  1780. , cbSrc
  1781. , MXUL_STYLEF_SOURCE
  1782. , &avcd[ivcd]);
  1783. if (!fAddLine)
  1784. {
  1785. return FALSE;
  1786. }
  1787. }
  1788. if (fFirstRun)
  1789. Volume_GetSetRegistryLineStates(pmxud->szMixer
  1790. , pmxud->avcd[0].szShortName
  1791. , avcd
  1792. , cvcd
  1793. , SET);
  1794. }
  1795. //
  1796. // Now that both arrays are now fixed, set back pointers for
  1797. // the vcd's to ui lines.
  1798. //
  1799. for (imxul = 0; imxul < pmxud->cmxul; imxul++)
  1800. {
  1801. pmxud->amxul[imxul].pvcd->pmxul = &pmxud->amxul[imxul];
  1802. //
  1803. // Accumulate support bits
  1804. //
  1805. dwSupport |= pmxud->amxul[imxul].pvcd->dwSupport;
  1806. }
  1807. //
  1808. // Support bits say we have no advanced controls, so don't make
  1809. // them available.
  1810. //
  1811. if (!(dwSupport & VCD_SUPPORTF_MIXER_ADVANCED))
  1812. {
  1813. pmxud->dwFlags |= MXUD_FLAGSF_NOADVANCED;
  1814. }
  1815. //
  1816. // Propogate bad driver bit to be app global. A bad driver was
  1817. // detected during the construction of a volume description.
  1818. //
  1819. for (ivcd = 0; ivcd < pmxud->cvcd; ivcd++)
  1820. {
  1821. if (pmxud->avcd[ivcd].dwSupport & VCD_SUPPORTF_BADDRIVER)
  1822. {
  1823. dlout("Bad Control->Line mapping. Marking bad driver.");
  1824. pmxud->dwFlags |= MXUD_FLAGSF_BADDRIVER;
  1825. break;
  1826. }
  1827. }
  1828. }
  1829. //
  1830. // Note: it isn't necessary to free/unlock the lpMaster/lpDst/lpSrc
  1831. // because they are ptr's to resources and Win32 is smart about resources
  1832. //
  1833. return (avcd != NULL);
  1834. }
  1835. /*
  1836. * Volume_DialogBox
  1837. *
  1838. * */
  1839. DWORD Volume_DialogBox(
  1840. PMIXUIDIALOG pmxud)
  1841. {
  1842. pmxud->dwReturn = MIXUI_EXIT;
  1843. if (Volume_CreateVolume(pmxud))
  1844. {
  1845. HWND hdlg;
  1846. if(NULL == pmxud->lpDialog)
  1847. {
  1848. Volume_Cleanup(pmxud);
  1849. return MIXUI_ERROR;
  1850. }
  1851. hdlg = CreateDialogIndirectParam(pmxud->hInstance
  1852. , (DLGTEMPLATE *)pmxud->lpDialog
  1853. , NULL
  1854. , VolumeProc
  1855. , (LPARAM)(LPVOID)pmxud );
  1856. if (!hdlg)
  1857. {
  1858. Volume_Cleanup(pmxud);
  1859. return MIXUI_ERROR;
  1860. }
  1861. else
  1862. {
  1863. // Unfortunately, re-registering the winclass does not re-apply any
  1864. // new icon correctly, so we must explicitly apply it here.
  1865. SendMessage (hdlg, WM_SETICON, (WPARAM) ICON_BIG,
  1866. (LPARAM) GetAppIcon (pmxud->hInstance, pmxud->mxid));
  1867. }
  1868. ShowWindow(hdlg, pmxud->nShowCmd);
  1869. }
  1870. else
  1871. {
  1872. return MIXUI_ERROR;
  1873. }
  1874. return (DWORD)(-1);
  1875. }
  1876. void DoHtmlHelp()
  1877. {
  1878. //note, using ANSI version of function because UNICODE is foobar in NT5 builds
  1879. char chDst[MAX_PATH];
  1880. WideCharToMultiByte(CP_ACP, 0, gszHtmlHelpFileName,
  1881. -1, chDst, MAX_PATH, NULL, NULL);
  1882. HtmlHelpA(GetDesktopWindow(), chDst, HH_DISPLAY_TOPIC, 0);
  1883. }
  1884. void ProcessHelp(HWND hwnd)
  1885. {
  1886. static TCHAR HelpFile[] = TEXT("SNDVOL32.HLP");
  1887. //Handle context menu help
  1888. if(bF1InMenu)
  1889. {
  1890. switch(currMenuItem)
  1891. {
  1892. case IDM_PROPERTIES:
  1893. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_PROPERTIES);
  1894. break;
  1895. case IDM_ADVANCED:
  1896. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_ADVANCED_CONTROLS);
  1897. break;
  1898. case IDM_EXIT:
  1899. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_OPTIONS_EXIT);
  1900. break;
  1901. case IDM_HELPTOPICS:
  1902. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_HELP_HELP_TOPICS);
  1903. break;
  1904. case IDM_HELPABOUT:
  1905. WinHelp(hwnd, HelpFile, HELP_CONTEXTPOPUP, IDH_SNDVOL32_HELP_ABOUT);
  1906. break;
  1907. default://In the default case just display the HTML Help.
  1908. DoHtmlHelp();
  1909. }
  1910. bF1InMenu = FALSE; //This flag will be set again if F1 is pressed in a menu.
  1911. }
  1912. else
  1913. DoHtmlHelp();
  1914. }
  1915. /*
  1916. * VolumeParent_WndProc
  1917. *
  1918. * A generic invisible parent window.
  1919. *
  1920. * */
  1921. LRESULT CALLBACK VolumeParent_WndProc(
  1922. HWND hwnd,
  1923. UINT msg,
  1924. WPARAM wparam,
  1925. LPARAM lparam)
  1926. {
  1927. PMIXUIDIALOG pmxud;
  1928. switch (msg)
  1929. {
  1930. case WM_CREATE:
  1931. {
  1932. LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lparam;
  1933. pmxud = (PMIXUIDIALOG)lpcs->lpCreateParams;
  1934. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pmxud);
  1935. pmxud->hParent = hwnd;
  1936. if (Volume_DialogBox(pmxud) == MIXUI_ERROR)
  1937. {
  1938. if ( !(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  1939. {
  1940. if ( Volume_NumDevs() == 0 )
  1941. Volume_ErrorMessageBox(NULL, pmxud->hInstance, IDS_ERR_NODEV);
  1942. else
  1943. Volume_ErrorMessageBox(NULL, pmxud->hInstance, IDS_ERR_HARDWARE);
  1944. }
  1945. PostMessage(hwnd, WM_CLOSE, 0, 0L);
  1946. }
  1947. return 0;
  1948. }
  1949. case WM_CLOSE:
  1950. DestroyWindow(hwnd);
  1951. return 0;
  1952. case WM_DESTROY:
  1953. //
  1954. // Post-close cleanup
  1955. //
  1956. pmxud = (PMIXUIDIALOG)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1957. if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP))
  1958. WinHelp(hwnd, gszHelpFileName, HELP_QUIT, 0L);
  1959. PostQuitMessage(0);
  1960. return 0;
  1961. case MYWM_HELPTOPICS:
  1962. //
  1963. // F1 Help
  1964. //
  1965. pmxud = (PMIXUIDIALOG)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1966. if (!(pmxud->dwStyle & MXUD_STYLEF_NOHELP))
  1967. {
  1968. ProcessHelp(hwnd);
  1969. }
  1970. break;
  1971. case MYWM_RESTART:
  1972. //
  1973. // A device change or other user property change caused a UI
  1974. // change. Sending a restart to the parent prevents ugly stuff
  1975. // like WinHelp shutting down and exiting our primary message
  1976. // loop.
  1977. //
  1978. pmxud = (PMIXUIDIALOG)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1979. if (!(pmxud->dwStyle & MXUD_STYLEF_TRAYMASTER))
  1980. {
  1981. if (Volume_NumDevs() == 0)
  1982. {
  1983. Volume_ErrorMessageBox(NULL
  1984. , pmxud->hInstance
  1985. , IDS_ERR_NODEV);
  1986. PostMessage(hwnd, WM_CLOSE, 0, 0L);
  1987. }
  1988. else if (Volume_DialogBox((PMIXUIDIALOG)lparam) == MIXUI_ERROR)
  1989. {
  1990. Volume_ErrorMessageBox(NULL
  1991. , pmxud->hInstance
  1992. , IDS_ERR_HARDWARE);
  1993. PostMessage(hwnd, WM_CLOSE, 0, 0L);
  1994. }
  1995. }
  1996. else
  1997. {
  1998. if (Mixer_GetNumDevs() == 0
  1999. || Volume_DialogBox((PMIXUIDIALOG)lparam) == MIXUI_ERROR)
  2000. PostMessage(hwnd, WM_CLOSE, 0, 0L);
  2001. }
  2002. break;
  2003. default:
  2004. break;
  2005. }
  2006. return (DefWindowProc(hwnd, msg, wparam, lparam));
  2007. }
  2008. const TCHAR szNull[] = TEXT ("");
  2009. /*
  2010. * Parent Dialog
  2011. * */
  2012. HWND VolumeParent_DialogMain(
  2013. PMIXUIDIALOG pmxud)
  2014. {
  2015. WNDCLASS wc;
  2016. HWND hwnd;
  2017. wc.lpszClassName = gszParentClass;
  2018. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  2019. wc.hIcon = NULL;
  2020. wc.lpszMenuName = NULL;
  2021. wc.hbrBackground = NULL;
  2022. wc.hInstance = pmxud->hInstance;
  2023. wc.style = 0;
  2024. wc.lpfnWndProc = VolumeParent_WndProc;
  2025. wc.cbClsExtra = 0;
  2026. wc.cbWndExtra = 0;
  2027. if (!RegisterClass(&wc))
  2028. return NULL;
  2029. hwnd = CreateWindow(gszParentClass
  2030. , szNull
  2031. , 0
  2032. , 0
  2033. , 0
  2034. , 0
  2035. , 0
  2036. , NULL
  2037. , NULL
  2038. , pmxud->hInstance
  2039. , (LPVOID)pmxud );
  2040. return hwnd;
  2041. }
  2042. /*
  2043. * Determines if what the recording destination ID
  2044. */
  2045. HRESULT GetRecordingDestID(int mxid, DWORD *piDest)
  2046. {
  2047. HRESULT hr = E_FAIL;
  2048. DWORD cDest;
  2049. int iDest;
  2050. MMRESULT mmr;
  2051. MIXERCAPS mxcaps;
  2052. if (piDest)
  2053. {
  2054. *piDest = 0;
  2055. mmr = mixerGetDevCaps(mxid, &mxcaps, sizeof(MIXERCAPS));
  2056. if (mmr == MMSYSERR_NOERROR)
  2057. {
  2058. cDest = mxcaps.cDestinations;
  2059. for (iDest = cDest - 1; iDest >= 0; iDest--)
  2060. {
  2061. MIXERLINE mlDst;
  2062. mlDst.cbStruct = sizeof ( mlDst );
  2063. mlDst.dwDestination = iDest;
  2064. if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR)
  2065. continue;
  2066. if (Mixer_IsValidRecordingDestination ((HMIXEROBJ)IntToPtr(mxid), &mlDst))
  2067. {
  2068. *piDest = iDest;
  2069. hr = S_OK;
  2070. break;
  2071. }
  2072. }
  2073. }
  2074. }
  2075. return(hr);
  2076. }
  2077. /*------------------------------------------------------+
  2078. | HelpMsgFilter - filter for F1 key in dialogs |
  2079. | |
  2080. +------------------------------------------------------*/
  2081. DWORD FAR PASCAL HelpMsgFilter(int nCode, UINT wParam, DWORD_PTR lParam)
  2082. {
  2083. if (nCode >= 0)
  2084. {
  2085. LPMSG msg = (LPMSG)lParam;
  2086. if (ghwndApp && (msg->message == WM_KEYDOWN) && (msg->wParam == VK_F1))
  2087. {
  2088. if(nCode == MSGF_MENU)
  2089. bF1InMenu = TRUE;
  2090. SendMessage(ghwndApp, WM_COMMAND, (WPARAM)IDM_HELPTOPICS, 0L);
  2091. }
  2092. }
  2093. return 0;
  2094. }
  2095. /*
  2096. * Returns the correct Destination ID for the specified device ID
  2097. */
  2098. HRESULT GetDestination(DWORD mxid, int *piDest)
  2099. {
  2100. if (gfRecord)
  2101. {
  2102. return GetDestLineID(mxid,piDest);
  2103. }
  2104. else
  2105. {
  2106. return GetSrcLineID(mxid,piDest);
  2107. }
  2108. }
  2109. /*
  2110. * Determines line ID
  2111. */
  2112. HRESULT GetDestLineID(int mxid, DWORD *piDest)
  2113. {
  2114. HRESULT hr = E_FAIL;
  2115. MIXERLINE mlDst;
  2116. if (piDest)
  2117. {
  2118. hr = S_OK;
  2119. *piDest = 0;
  2120. mlDst.cbStruct = sizeof ( mlDst );
  2121. mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
  2122. if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
  2123. {
  2124. *piDest = mlDst.dwDestination;
  2125. }
  2126. }
  2127. return(hr);
  2128. }
  2129. /*
  2130. * Determines line ID
  2131. */
  2132. HRESULT GetSrcLineID(int mxid, DWORD *piDest)
  2133. {
  2134. HRESULT hr = E_FAIL;
  2135. MIXERLINE mlDst;
  2136. if (piDest)
  2137. {
  2138. hr = S_OK;
  2139. *piDest = 0;
  2140. mlDst.cbStruct = sizeof ( mlDst );
  2141. mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  2142. if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR)
  2143. {
  2144. *piDest = mlDst.dwDestination;
  2145. }
  2146. else
  2147. {
  2148. mlDst.cbStruct = sizeof ( mlDst );
  2149. mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
  2150. if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR)
  2151. {
  2152. *piDest = mlDst.dwDestination;
  2153. }
  2154. else
  2155. {
  2156. mlDst.cbStruct = sizeof ( mlDst );
  2157. mlDst.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
  2158. if (mixerGetLineInfo((HMIXEROBJ)IntToPtr(mxid), &mlDst, MIXER_GETLINEINFOF_COMPONENTTYPE ) == MMSYSERR_NOERROR)
  2159. {
  2160. *piDest = mlDst.dwDestination;
  2161. }
  2162. }
  2163. }
  2164. }
  2165. return(hr);
  2166. }
  2167. /* - - - - - - - - - */
  2168. /*
  2169. * entry point
  2170. * */
  2171. int WINAPI WinMain(
  2172. HINSTANCE hInst,
  2173. HINSTANCE hPrev,
  2174. LPSTR lpCmdLine,
  2175. int nShowCmd)
  2176. {
  2177. int err = 0;
  2178. MIXUIDIALOG mxud;
  2179. MSG msg;
  2180. HWND hwnd;
  2181. HANDLE hAccel;
  2182. MMRESULT mmr;
  2183. TCHAR ach[2];
  2184. UINT u;
  2185. BOOL fGotDevice = FALSE;
  2186. UINT uDeviceID;
  2187. ach[0] = '\0'; // PREFIX complains if we do not init this.
  2188. LoadString(hInst, IDS_IS_RTL, ach, SIZEOF(ach));
  2189. gfIsRTL = ach[0] == TEXT('1');
  2190. //
  2191. // initialize the app instance data
  2192. //
  2193. ZeroMemory(&mxud, sizeof(mxud));
  2194. mxud.hInstance = hInst;
  2195. mxud.dwFlags = MXUD_FLAGSF_MIXER;
  2196. /* setup the message filter to handle grabbing F1 for this task */
  2197. fpfnMsgHook = (HOOKPROC)MakeProcInstance((FARPROC)HelpMsgFilter, ghInst);
  2198. fpfnOldMsgFilter = (HHOOK)SetWindowsHook(WH_MSGFILTER, fpfnMsgHook);
  2199. //
  2200. // parse the command line for "/T"
  2201. //
  2202. u = 0;
  2203. while (lpCmdLine[u] != '\0')
  2204. {
  2205. switch (lpCmdLine[u])
  2206. {
  2207. case TEXT('-'):
  2208. case TEXT('/'):
  2209. {
  2210. u++;
  2211. if (lpCmdLine[u] != '\0')
  2212. {
  2213. switch (lpCmdLine[u])
  2214. {
  2215. case TEXT('T'):
  2216. case TEXT('t'):
  2217. mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER;
  2218. u++;
  2219. break;
  2220. case TEXT('S'):
  2221. case TEXT('s'):
  2222. mxud.dwStyle |= MXUD_STYLEF_SMALL;
  2223. u++;
  2224. break;
  2225. case TEXT('R'): // Should run in Record mode, not Playback (default)
  2226. case TEXT('r'):
  2227. gfRecord = TRUE;
  2228. u++;
  2229. break;
  2230. case TEXT('X'):
  2231. case TEXT('x'):
  2232. mxud.dwStyle |= MXUD_STYLEF_TRAYMASTER | MXUD_STYLEF_CLOSE;
  2233. break;
  2234. case TEXT('D'): // Should use the specified device
  2235. case TEXT('d'):
  2236. {
  2237. u++; // Skip "d" and any following spaces
  2238. while (lpCmdLine[u] != '\0' && isspace(lpCmdLine[u]))
  2239. {
  2240. u++;
  2241. }
  2242. if (lpCmdLine[u] != '\0')
  2243. {
  2244. char szDeviceID[255];
  2245. UINT uDev = 0;
  2246. while ((uDev < 2) && lpCmdLine[u] != '\0' && !isalpha(lpCmdLine[u]) && !isspace(lpCmdLine[u]))
  2247. {
  2248. szDeviceID[uDev] = lpCmdLine[u];
  2249. u++;
  2250. uDev++;
  2251. }
  2252. szDeviceID[uDev] = '\0';
  2253. uDeviceID = strtoul(szDeviceID,NULL,10);
  2254. fGotDevice = TRUE;
  2255. }
  2256. }
  2257. break;
  2258. default: // Unknown Command, just ignore it.
  2259. u++;
  2260. break;
  2261. }
  2262. }
  2263. }
  2264. break;
  2265. default:
  2266. {
  2267. u++;
  2268. }
  2269. break;
  2270. }
  2271. }
  2272. //
  2273. // Restore last style
  2274. //
  2275. if (!(mxud.dwStyle & (MXUD_STYLEF_TRAYMASTER|MXUD_STYLEF_SMALL)))
  2276. {
  2277. Volume_GetSetStyle(&mxud.dwStyle, GET);
  2278. }
  2279. if (mxud.dwStyle & MXUD_STYLEF_TRAYMASTER)
  2280. {
  2281. HWND hwndSV;
  2282. //
  2283. // Locate a waiting instance of the tray volume and wake it up
  2284. //
  2285. hwndSV = FindWindow(gszTrayClassName, NULL);
  2286. if (hwndSV) {
  2287. SendMessage(hwndSV, MYWM_WAKEUP,
  2288. (mxud.dwStyle & MXUD_STYLEF_CLOSE), 0);
  2289. goto mxendapp;
  2290. }
  2291. }
  2292. if (mxud.dwStyle & MXUD_STYLEF_CLOSE) {
  2293. goto mxendapp;
  2294. }
  2295. //
  2296. // Init to the default mixer
  2297. //
  2298. if (fGotDevice)
  2299. {
  2300. UINT cWaves;
  2301. if (gfRecord)
  2302. {
  2303. cWaves = waveInGetNumDevs();
  2304. }
  2305. else
  2306. {
  2307. cWaves = waveOutGetNumDevs();
  2308. }
  2309. if (uDeviceID >= cWaves)
  2310. {
  2311. fGotDevice = FALSE;
  2312. }
  2313. }
  2314. if (!fGotDevice)
  2315. {
  2316. mmr = Volume_GetDefaultMixerID(&mxud.mxid, gfRecord);
  2317. }
  2318. else
  2319. {
  2320. mxud.mxid = uDeviceID;
  2321. }
  2322. if (gfRecord)
  2323. {
  2324. if (FAILED(GetRecordingDestID(mxud.mxid,&mxud.iDest)))
  2325. {
  2326. goto mxendapp;
  2327. }
  2328. }
  2329. else
  2330. {
  2331. if (FAILED(GetDestination(mxud.mxid,&mxud.iDest)))
  2332. {
  2333. goto mxendapp;
  2334. }
  2335. }
  2336. //
  2337. // For the tray master, get the mix id associated with the default
  2338. // wave device. If this fails, go away.
  2339. //
  2340. if (mxud.dwStyle & MXUD_STYLEF_TRAYMASTER)
  2341. {
  2342. if (mmr != MMSYSERR_NOERROR)
  2343. goto mxendapp;
  2344. mxud.dwStyle |= MXUD_STYLEF_NOHELP;
  2345. mxud.nShowCmd = SW_HIDE;
  2346. }
  2347. else
  2348. {
  2349. if (!Volume_NumDevs())
  2350. {
  2351. Volume_ErrorMessageBox(NULL, hInst, IDS_ERR_NODEV);
  2352. goto mxendapp;
  2353. }
  2354. InitVUControl(hInst);
  2355. if (!LoadString(hInst
  2356. , IDS_HELPFILENAME
  2357. , gszHelpFileName
  2358. , SIZEOF(gszHelpFileName)))
  2359. mxud.dwStyle |= MXUD_STYLEF_NOHELP;
  2360. if (!LoadString(hInst
  2361. , IDS_HTMLHELPFILENAME
  2362. , gszHtmlHelpFileName
  2363. , SIZEOF(gszHtmlHelpFileName)))
  2364. mxud.dwStyle |= MXUD_STYLEF_NOHELP;
  2365. mxud.nShowCmd = (nShowCmd == SW_SHOWMAXIMIZED)
  2366. ? SW_SHOWNORMAL:nShowCmd;
  2367. if (!(mxud.dwStyle & MXUD_STYLEF_SMALL))
  2368. mxud.dwStyle |= MXUD_STYLEF_STATUS; // has status bar
  2369. }
  2370. //
  2371. // Use the common controls
  2372. //
  2373. InitCommonControls();
  2374. hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_VOLUMEACCEL));
  2375. hwnd = VolumeParent_DialogMain(&mxud);
  2376. //Initialize the handle which the hook for F1 help will use.
  2377. ghwndApp = mxud.hwnd;
  2378. if (hwnd)
  2379. {
  2380. while (GetMessage(&msg, NULL, 0, 0))
  2381. {
  2382. if (mxud.hwnd) {
  2383. if (hAccel && TranslateAccelerator(mxud.hwnd, hAccel, &msg))
  2384. continue;
  2385. if (IsDialogMessage(mxud.hwnd,&msg))
  2386. continue;
  2387. }
  2388. TranslateMessage(&msg);
  2389. DispatchMessage(&msg);
  2390. }
  2391. }
  2392. mxendapp:
  2393. /* if the message hook was installed, remove it and free */
  2394. /* up our proc instance for it. */
  2395. if (fpfnOldMsgFilter){
  2396. UnhookWindowsHook(WH_MSGFILTER, fpfnMsgHook);
  2397. }
  2398. return err;
  2399. }
  2400. void FreeAppIcon ()
  2401. {
  2402. if (ghiconApp)
  2403. {
  2404. DestroyIcon (ghiconApp);
  2405. ghiconApp = NULL;
  2406. }
  2407. }
  2408. // TODO: Move to "regstr.h"
  2409. #define REGSTR_KEY_BRANDING TEXT("Branding")
  2410. #define REGSTR_VAL_AUDIO_BITMAP TEXT("bitmap")
  2411. #define REGSTR_VAL_AUDIO_ICON TEXT("icon")
  2412. #define REGSTR_VAL_AUDIO_URL TEXT("url")
  2413. HKEY OpenDeviceBrandRegKey (UINT uiMixID)
  2414. {
  2415. HKEY hkeyBrand = NULL;
  2416. HKEY hkeyDevice = OpenDeviceRegKey (uiMixID, KEY_READ);
  2417. if (hkeyDevice)
  2418. {
  2419. if (ERROR_SUCCESS != RegOpenKeyEx (hkeyDevice, REGSTR_KEY_BRANDING, 0, KEY_READ, &hkeyBrand))
  2420. hkeyBrand = NULL; // Make sure NULL on failure
  2421. // Close the Device key
  2422. RegCloseKey (hkeyDevice);
  2423. }
  2424. return hkeyBrand;
  2425. }
  2426. ///////////////////////////////////////////////////////////////////////////////////////////
  2427. // Microsoft Confidential - DO NOT COPY THIS METHOD INTO ANY APPLICATION, THIS MEANS YOU!!!
  2428. ///////////////////////////////////////////////////////////////////////////////////////////
  2429. PTCHAR GetInterfaceName (DWORD dwMixerID)
  2430. {
  2431. MMRESULT mmr;
  2432. ULONG cbSize=0;
  2433. TCHAR *szInterfaceName=NULL;
  2434. //Query for the Device interface name
  2435. mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L);
  2436. if(MMSYSERR_NOERROR == mmr)
  2437. {
  2438. szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR));
  2439. if(!szInterfaceName)
  2440. {
  2441. return NULL;
  2442. }
  2443. mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize);
  2444. if(MMSYSERR_NOERROR != mmr)
  2445. {
  2446. GlobalFreePtr(szInterfaceName);
  2447. return NULL;
  2448. }
  2449. }
  2450. return szInterfaceName;
  2451. }
  2452. HKEY OpenDeviceRegKey (UINT uiMixID, REGSAM sam)
  2453. {
  2454. HKEY hkeyDevice = NULL;
  2455. PTCHAR szInterfaceName = GetInterfaceName (uiMixID);
  2456. if (szInterfaceName)
  2457. {
  2458. HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList (NULL, NULL);
  2459. if (INVALID_HANDLE_VALUE != DeviceInfoSet)
  2460. {
  2461. SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
  2462. DeviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
  2463. if (SetupDiOpenDeviceInterface (DeviceInfoSet, szInterfaceName,
  2464. 0, &DeviceInterfaceData))
  2465. {
  2466. DWORD dwRequiredSize;
  2467. SP_DEVINFO_DATA DeviceInfoData;
  2468. DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
  2469. // Ignore error, it always returns "ERROR_INSUFFICIENT_BUFFER" even though
  2470. // the "SP_DEVICE_INTERFACE_DETAIL_DATA" parameter is supposed to be optional.
  2471. (void) SetupDiGetDeviceInterfaceDetail (DeviceInfoSet, &DeviceInterfaceData,
  2472. NULL, 0, &dwRequiredSize, &DeviceInfoData);
  2473. // Open device reg key
  2474. hkeyDevice = SetupDiOpenDevRegKey (DeviceInfoSet, &DeviceInfoData,
  2475. DICS_FLAG_GLOBAL, 0,
  2476. DIREG_DRV, sam);
  2477. }
  2478. SetupDiDestroyDeviceInfoList (DeviceInfoSet);
  2479. }
  2480. GlobalFreePtr (szInterfaceName);
  2481. }
  2482. return hkeyDevice;
  2483. }
  2484. HICON GetAppIcon (HINSTANCE hInst, UINT uiMixID)
  2485. {
  2486. HKEY hkeyBrand = OpenDeviceBrandRegKey (uiMixID);
  2487. FreeAppIcon ();
  2488. if (hkeyBrand)
  2489. {
  2490. WCHAR szBuffer[MAX_PATH];
  2491. DWORD dwType = REG_SZ;
  2492. DWORD cb = sizeof (szBuffer);
  2493. if (ERROR_SUCCESS == RegQueryValueEx (hkeyBrand, REGSTR_VAL_AUDIO_ICON, NULL, &dwType, (LPBYTE)szBuffer, &cb))
  2494. {
  2495. if (REG_SZ == dwType)
  2496. {
  2497. WCHAR* pszComma = wcschr (szBuffer, L',');
  2498. if (pszComma)
  2499. {
  2500. WCHAR* pszResourceID = pszComma + 1;
  2501. HANDLE hResource;
  2502. // Remove comma delimeter
  2503. *pszComma = L'\0';
  2504. // Should be a resource module and a resource ID
  2505. hResource = LoadLibrary (szBuffer);
  2506. if (!hResource)
  2507. {
  2508. TCHAR szDriversPath[MAX_PATH];
  2509. // If we didn't find it on the normal search path, try looking
  2510. // in the "drivers" directory.
  2511. if (GetSystemDirectory (szDriversPath, MAX_PATH))
  2512. {
  2513. HRESULT hr = StringCchCat(szDriversPath, SIZEOF(szDriversPath), TEXT("\\drivers\\"));
  2514. if( hr == S_OK )
  2515. {
  2516. hr = StringCchCat(szDriversPath, SIZEOF(szDriversPath), szBuffer);
  2517. if( hr == S_OK )
  2518. {
  2519. hResource = LoadLibrary (szDriversPath);
  2520. }
  2521. }
  2522. }
  2523. }
  2524. if (hResource)
  2525. {
  2526. ghiconApp = LoadImage (hResource, MAKEINTRESOURCE(_wtoi (pszResourceID)), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  2527. FreeLibrary (hResource);
  2528. }
  2529. }
  2530. else
  2531. // Should be an *.ico file
  2532. ghiconApp = LoadImage (NULL, szBuffer, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
  2533. }
  2534. }
  2535. RegCloseKey (hkeyBrand);
  2536. // Return the custom icon
  2537. if (ghiconApp)
  2538. return ghiconApp;
  2539. }
  2540. return (LoadIcon (hInst, MAKEINTRESOURCE (IDI_MIXER)));
  2541. }