xref: /reactos/base/applications/sndvol32/dialog.c (revision 23373acb)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS Sound Volume Control
4  * FILE:        base/applications/sndvol32/dialog.c
5  * PROGRAMMERS: Johannes Anderwald
6  */
7 
8 #include "sndvol32.h"
9 
10 
11 VOID
12 ConvertRect(LPRECT lpRect, UINT xBaseUnit, UINT yBaseUnit)
13 {
14     lpRect->left = MulDiv(lpRect->left, xBaseUnit, 4);
15     lpRect->right = MulDiv(lpRect->right, xBaseUnit, 4);
16     lpRect->top = MulDiv(lpRect->top, yBaseUnit, 8);
17     lpRect->bottom = MulDiv(lpRect->bottom, yBaseUnit, 8);
18 }
19 
20 LPVOID
21 LoadDialogResource(
22     IN HMODULE hModule,
23     IN LPCWSTR ResourceName,
24     OUT LPDWORD ResourceLength)
25 {
26     HRSRC hSrc;
27     HGLOBAL hRes;
28     PVOID Result;
29 
30     /* find resource */
31     hSrc = FindResourceW(hModule, ResourceName, (LPCWSTR)RT_DIALOG);
32 
33     if (!hSrc)
34     {
35         /* failed to find resource */
36         return NULL;
37     }
38 
39     /* now load the resource */
40     hRes = LoadResource(hAppInstance, hSrc);
41     if (!hRes)
42     {
43         /* failed to load resource */
44         return NULL;
45     }
46 
47     /* now lock the resource */
48     Result = LockResource(hRes);
49 
50     if (!Result)
51     {
52         /* failed to lock resource */
53         return NULL;
54     }
55 
56     if (ResourceLength)
57     {
58         /* store output length */
59         *ResourceLength = SizeofResource(hAppInstance, hSrc);
60     }
61 
62     /* done */
63     return Result;
64 }
65 
66 LPWORD
67 AddDialogControl(
68     IN HWND hwndDialog,
69     OUT HWND *OutWnd,
70     IN LPRECT DialogOffset,
71     IN PDLGITEMTEMPLATE DialogItem,
72     IN DWORD DialogIdMultiplier,
73     IN HFONT hFont,
74     IN UINT xBaseUnit,
75     IN UINT yBaseUnit,
76     IN UINT MixerId)
77 {
78     RECT rect;
79     LPWORD Offset;
80     LPWSTR ClassName, WindowName;
81     WCHAR WindowIdBuf[sizeof("#65535")];
82     HWND hwnd;
83     DWORD wID;
84     INT nSteps, i;
85 
86     /* initialize client rectangle */
87     rect.left = DialogItem->x;
88     rect.top = DialogItem->y;
89     rect.right = DialogItem->x + DialogItem->cx;
90     rect.bottom = DialogItem->y + DialogItem->cy;
91 
92     /* Convert Dialog units to pixes */
93     ConvertRect(&rect, xBaseUnit, yBaseUnit);
94 
95     rect.left += DialogOffset->left;
96     rect.right += DialogOffset->left;
97     rect.top += DialogOffset->top;
98     rect.bottom += DialogOffset->top;
99 
100     /* move offset after dialog item */
101     Offset = (LPWORD)(DialogItem + 1);
102 
103     if (*Offset == 0xFFFF)
104     {
105         /* class is encoded as type */
106         Offset++;
107 
108         /* get control type */
109         switch(*Offset)
110         {
111             case 0x80:
112                 ClassName = L"button";
113                 break ;
114             case 0x82:
115                 ClassName = L"static";
116                 break;
117             default:
118                /* FIXME */
119                assert(0);
120                ClassName = NULL;
121         }
122         Offset++;
123     }
124     else
125     {
126         /* class name is encoded as string */
127         ClassName = (LPWSTR)(Offset);
128 
129         /* move offset to the end of class string */
130         Offset += wcslen(ClassName) + 1;
131     }
132 
133     if (*Offset == 0xFFFF)
134     {
135         /* Window name is encoded as ordinal */
136         Offset++;
137         wsprintf(WindowIdBuf, L"#%u", (DWORD)*Offset);
138         WindowName = WindowIdBuf;
139         Offset++;
140     }
141     else
142     {
143         /* window name is encoded as string */
144         WindowName = (LPWSTR)(Offset);
145 
146         /* move offset to the end of class string */
147         Offset += wcslen(WindowName) + 1;
148     }
149 
150     if (DialogItem->id == MAXWORD)
151     {
152         /* id is not important */
153         wID = DialogItem->id;
154     }
155     else
156     {
157         /* calculate id */
158         wID = DialogItem->id * (DialogIdMultiplier + 1);
159 
160     }
161 
162     /* now create the window */
163     hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
164                            ClassName,
165                            WindowName,
166                            DialogItem->style,
167                            rect.left,
168                            rect.top,
169                            rect.right - rect.left,
170                            rect.bottom - rect.top,
171                            hwndDialog,
172                            UlongToPtr(wID),
173                            hAppInstance,
174                            NULL);
175 
176     /* sanity check */
177     assert(hwnd);
178 
179     /* store window */
180     *OutWnd = hwnd;
181 
182     /* check if this the track bar */
183     if (!wcsicmp(ClassName, L"msctls_trackbar32"))
184     {
185         if (DialogItem->style & TBS_VERT)
186         {
187             /* Vertical trackbar: Volume */
188 
189             /* Disable the volume trackbar by default */
190             EnableWindow(hwnd, FALSE);
191 
192             /* set up range */
193             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
194 
195             /* set up page size */
196             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
197 
198             /* set position */
199             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
200 
201             /* Calculate and set ticks */
202             nSteps = (VOLUME_MAX / (VOLUME_TICKS + 1));
203             if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
204                 nSteps++;
205             for (i = nSteps; i < VOLUME_MAX; i += nSteps)
206                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
207         }
208         else
209         {
210             /* Horizontal trackbar: Balance */
211 
212             /* Disable the balance trackbar by default */
213             EnableWindow(hwnd, FALSE);
214 
215             /* set up range */
216             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, BALANCE_STEPS));
217 
218             /* set up page size */
219             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)BALANCE_PAGE_SIZE);
220 
221             /* set position */
222             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)BALANCE_STEPS / 2);
223 
224             /* Calculate and set ticks */
225             nSteps = (BALANCE_STEPS / (BALANCE_TICKS + 1));
226             if (BALANCE_STEPS % (BALANCE_TICKS + 1) != 0)
227                 nSteps++;
228             for (i = nSteps; i < BALANCE_STEPS; i += nSteps)
229                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
230         }
231     }
232     else if (!wcsicmp(ClassName, L"static"))
233     {
234         /* Set font */
235         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
236     }
237     else if (!wcsicmp(ClassName, L"button"))
238     {
239         if (DialogItem->id == IDC_LINE_SWITCH)
240         {
241             if (MixerId == PLAY_MIXER)
242             {
243                 /* Disable checkboxes by default, if we are in play mode */
244                 EnableWindow(hwnd, FALSE);
245             }
246         }
247         else if (DialogItem->id == IDC_LINE_ADVANCED)
248         {
249             ShowWindow(hwnd, SW_HIDE);
250         }
251 
252         /* Set font */
253         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
254     }
255 
256 
257     /* check if there is additional data */
258     if (*Offset == 0)
259     {
260         /* no additional data */
261         Offset++;
262     }
263     else
264     {
265         /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
266         /* skip past additional data */
267         Offset += *Offset;
268     }
269 
270     /* make sure next template is word-aligned */
271     Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3);
272 
273     /* done */
274     return Offset;
275 }
276 
277 VOID
278 LoadDialogControls(
279     IN PMIXER_WINDOW MixerWindow,
280     LPRECT DialogOffset,
281     WORD ItemCount,
282     PDLGITEMTEMPLATE DialogItem,
283     DWORD DialogIdMultiplier,
284     UINT xBaseUnit,
285     UINT yBaseUnit)
286 {
287     LPWORD Offset;
288     WORD Index;
289 
290     /* sanity check */
291     assert(ItemCount);
292 
293     if (MixerWindow->Window)
294         MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + ItemCount) * sizeof(HWND));
295     else
296         MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ItemCount * sizeof(HWND));
297     if (!MixerWindow->Window)
298     {
299         /* no memory */
300         return;
301     }
302 
303     /* enumerate now all controls */
304     for (Index = 0; Index < ItemCount; Index++)
305     {
306         /* add controls */
307         Offset = AddDialogControl(MixerWindow->hWnd,
308                                   &MixerWindow->Window[MixerWindow->WindowCount],
309                                   DialogOffset,
310                                   DialogItem,
311                                   DialogIdMultiplier,
312                                   MixerWindow->hFont,
313                                   xBaseUnit,
314                                   yBaseUnit,
315                                   MixerWindow->MixerId);
316 
317         /* sanity check */
318         assert(Offset);
319 
320         /* move dialog item to new offset */
321         DialogItem =(PDLGITEMTEMPLATE)Offset;
322 
323         /* increment window count */
324         MixerWindow->WindowCount++;
325     }
326 }
327 
328 VOID
329 LoadDialog(
330     IN HMODULE hModule,
331     IN PMIXER_WINDOW MixerWindow,
332     IN LPCWSTR DialogResId,
333     IN DWORD Index)
334 {
335     LPDLGTEMPLATE DlgTemplate;
336     PDLGITEMTEMPLATE DlgItem;
337     RECT dialogRect;
338     LPWORD Offset;
339     WORD FontSize;
340     WCHAR FontName[100];
341     WORD Length;
342     int width;
343 
344     DWORD units = GetDialogBaseUnits();
345     UINT xBaseUnit = LOWORD(units);
346     UINT yBaseUnit = HIWORD(units);
347 
348     /* first load the dialog resource */
349     DlgTemplate = (LPDLGTEMPLATE)LoadDialogResource(hModule, DialogResId, NULL);
350     if (!DlgTemplate)
351     {
352         /* failed to load resource */
353         return;
354     }
355 
356     /* Now walk past the dialog header */
357     Offset = (LPWORD)(DlgTemplate + 1);
358 
359     /* FIXME: support menu */
360     assert(*Offset == 0);
361     Offset++;
362 
363     /* FIXME: support classes */
364     assert(*Offset == 0);
365     Offset++;
366 
367     /* FIXME: support titles */
368     assert(*Offset == 0);
369     Offset++;
370 
371     /* get font size */
372     FontSize = *Offset;
373     Offset++;
374 
375     /* calculate font length */
376     Length = wcslen((LPWSTR)Offset) + 1;
377     assert(Length < (sizeof(FontName) / sizeof(WCHAR)));
378 
379     /* copy font */
380     wcscpy(FontName, (LPWSTR)Offset);
381 
382     if (DlgTemplate->style & DS_SETFONT)
383     {
384         HDC hDC;
385 
386         hDC = GetDC(0);
387 
388         if (!MixerWindow->hFont)
389         {
390             int pixels = MulDiv(FontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
391             MixerWindow->hFont = CreateFontW(-pixels, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, FontName);
392         }
393 
394         if (MixerWindow->hFont)
395         {
396             SIZE charSize;
397             HFONT hOldFont;
398 
399             hOldFont = SelectObject(hDC, MixerWindow->hFont);
400             charSize.cx = GdiGetCharDimensions(hDC, NULL, &charSize.cy);
401             if (charSize.cx)
402             {
403                 xBaseUnit = charSize.cx;
404                 yBaseUnit = charSize.cy;
405             }
406             SelectObject(hDC, hOldFont);
407 
408             MixerWindow->baseUnit.cx = charSize.cx;
409             MixerWindow->baseUnit.cy = charSize.cy;
410         }
411     }
412 
413 //    assert(MixerWindow->hFont);
414 
415     /* move offset after font name */
416     Offset += Length;
417 
418     /* offset is now at first dialog item control */
419     DlgItem = (PDLGITEMTEMPLATE)Offset;
420 
421     dialogRect.left = 0;
422     dialogRect.right = DlgTemplate->cx;
423     dialogRect.top = 0;
424     dialogRect.bottom = DlgTemplate->cy;
425 
426     ConvertRect(&dialogRect, xBaseUnit, yBaseUnit);
427 
428     width = dialogRect.right - dialogRect.left;
429 
430     dialogRect.left += MixerWindow->rect.right;
431     dialogRect.right += MixerWindow->rect.right;
432     dialogRect.top += MixerWindow->rect.top;
433     dialogRect.bottom += MixerWindow->rect.top;
434 
435     MixerWindow->rect.right += width;
436     if ((dialogRect.bottom - dialogRect.top) > (MixerWindow->rect.bottom - MixerWindow->rect.top))
437         MixerWindow->rect.bottom = MixerWindow->rect.top + dialogRect.bottom - dialogRect.top;
438 
439     /* now add the controls */
440     LoadDialogControls(MixerWindow, &dialogRect, DlgTemplate->cdit, DlgItem, Index, xBaseUnit, yBaseUnit);
441 }
442 
443 BOOL
444 CALLBACK
445 EnumConnectionsCallback(
446     PSND_MIXER Mixer,
447     DWORD LineID,
448     LPMIXERLINE Line,
449     PVOID Context)
450 {
451     WCHAR LineName[MIXER_LONG_NAME_CHARS];
452     DWORD Flags;
453     DWORD wID;
454     UINT ControlCount = 0, Index;
455     LPMIXERCONTROL Control = NULL;
456     HWND hDlgCtrl;
457     PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
458     PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
459 
460     if (Line->cControls == 0)
461         return TRUE;
462 
463     /* get line name */
464     if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
465     {
466         /* failed to get line name */
467         LineName[0] = L'\0';
468     }
469 
470     pVolumeDetails = HeapAlloc(GetProcessHeap(),
471                                0,
472                                Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
473     if (pVolumeDetails == NULL)
474         goto done;
475 
476     /* check if line is found in registry settings */
477     if (ReadLineConfig(PrefContext->DeviceName,
478                        LineName,
479                        Line->szName,
480                        &Flags))
481     {
482           /* is it selected */
483           if (Flags != 0x4)
484           {
485               int dlgId;
486 
487               if ((Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) ||
488                   (Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES))
489                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_MASTER : IDD_NORMAL_MASTER;
490               else
491                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_LINE : IDD_NORMAL_LINE;
492 
493               /* load dialog resource */
494               LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(dlgId), PrefContext->MixerWindow->DialogCount);
495 
496               /* get id */
497               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_NAME;
498 
499               /* set line name */
500               SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
501 
502               /* query controls */
503               if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) != FALSE)
504               {
505                   /* now go through all controls and update their states */
506                   for (Index = 0; Index < Line->cControls; Index++)
507                   {
508                       if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
509                       {
510                           MIXERCONTROLDETAILS_BOOLEAN Details;
511 
512                           /* get volume control details */
513                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
514                           {
515                               /* update dialog control */
516                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SWITCH;
517 
518                               /* get dialog control */
519                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
520 
521                               if (hDlgCtrl != NULL)
522                               {
523                                   /* Enable the 'Mute' checkbox, if we are in play mode */
524                                   if (Mixer->MixerId == PLAY_MIXER)
525                                       EnableWindow(hDlgCtrl, TRUE);
526 
527                                   /* check state */
528                                   if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
529                                   {
530                                       /* update control state */
531                                       SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
532                                   }
533                               }
534                           }
535                       }
536                       else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
537                       {
538                           /* get volume control details */
539                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
540                           {
541                               /* update dialog control */
542                               DWORD volumePosition, volumeStep, maxVolume, i;
543                               DWORD balancePosition, balanceStep;
544 
545                               volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
546 
547                               maxVolume = 0;
548                               for (i = 0; i < Line->cChannels; i++)
549                               {
550                                   if (pVolumeDetails[i].dwValue > maxVolume)
551                                       maxVolume = pVolumeDetails[i].dwValue;
552                               }
553 
554                               volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
555 
556                               if (Line->cChannels == 1)
557                               {
558                                   balancePosition = BALANCE_CENTER;
559                               }
560                               else if (Line->cChannels == 2)
561                               {
562                                   if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
563                                   {
564                                       balancePosition = BALANCE_CENTER;
565                                   }
566                                   else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
567                                   {
568                                       balancePosition = BALANCE_RIGHT;
569                                   }
570                                   else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
571                                   {
572                                       balancePosition = BALANCE_LEFT;
573                                   }
574                                   else
575                                   {
576                                       balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
577 
578                                       if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
579                                       {
580                                           balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
581                                           balancePosition = BALANCE_RIGHT - balancePosition;
582                                       }
583                                       else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
584                                       {
585                                           balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
586                                           balancePosition = BALANCE_LEFT + balancePosition;
587                                       }
588                                   }
589                               }
590 
591                               /* Set the volume trackbar */
592                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_VERT;
593 
594                               /* get dialog control */
595                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
596 
597                               if (hDlgCtrl != NULL)
598                               {
599                                   /* check state */
600                                   LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
601 
602                                   /* Enable the volume trackbar */
603                                   EnableWindow(hDlgCtrl, TRUE);
604 
605                                   if (OldPosition != (VOLUME_MAX - volumePosition))
606                                   {
607                                       /* update control state */
608                                       SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, VOLUME_MAX - volumePosition);
609                                   }
610                               }
611 
612                               if (Line->cChannels == 2)
613                               {
614                                   /* Set the balance trackbar */
615                                   wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_HORZ;
616 
617                                   /* get dialog control */
618                                   hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
619 
620                                   if (hDlgCtrl != NULL)
621                                   {
622                                       /* check state */
623                                       LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
624 
625                                       /* Enable the balance trackbar */
626                                       EnableWindow(hDlgCtrl, TRUE);
627 
628                                       if (OldPosition != balancePosition)
629                                       {
630                                           /* update control state */
631                                           SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, balancePosition);
632                                       }
633                                   }
634                               }
635                           }
636                       }
637                       else
638                       {
639                           if (PrefContext->MixerWindow->Mode == NORMAL_MODE)
640                           {
641                               PrefContext->MixerWindow->bHasExtendedControls = TRUE;
642 
643                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_ADVANCED;
644 
645                               /* get dialog control */
646                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
647                               if (hDlgCtrl != NULL)
648                               {
649                                   ShowWindow(hDlgCtrl,
650                                              PrefContext->MixerWindow->bShowExtendedControls ? SW_SHOWNORMAL : SW_HIDE);
651                               }
652                           }
653                       }
654                   }
655 
656                   /* free controls */
657                   HeapFree(GetProcessHeap(), 0, Control);
658               }
659 
660               /* increment dialog count */
661               PrefContext->MixerWindow->DialogCount++;
662           }
663     }
664 
665 done:
666     /* Free the volume details */
667     if (pVolumeDetails)
668         HeapFree(GetProcessHeap(), 0, pVolumeDetails);
669 
670     return TRUE;
671 }
672 
673 VOID
674 LoadDialogCtrls(
675     PPREFERENCES_CONTEXT PrefContext)
676 {
677     WCHAR szBuffer[64];
678     HWND hDlgCtrl;
679     RECT statusRect;
680     UINT i;
681     LONG dy;
682 
683     /* set dialog count to zero */
684     PrefContext->MixerWindow->DialogCount = 0;
685     PrefContext->MixerWindow->bHasExtendedControls = FALSE;
686     SetRectEmpty(&PrefContext->MixerWindow->rect);
687 
688     /* enumerate controls */
689     SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
690 
691     /* Update the 'Advanced Controls' menu item */
692     EnableMenuItem(GetMenu(PrefContext->MixerWindow->hWnd),
693                    IDM_ADVANCED_CONTROLS,
694                    MF_BYCOMMAND | (PrefContext->MixerWindow->bHasExtendedControls ? MF_ENABLED : MF_GRAYED));
695 
696     /* Add some height for the status bar */
697     if (PrefContext->MixerWindow->hStatusBar)
698     {
699         GetWindowRect(PrefContext->MixerWindow->hStatusBar, &statusRect);
700         PrefContext->MixerWindow->rect.bottom += (statusRect.bottom - statusRect.top);
701     }
702 
703     /* Add height of the 'Advanced' button */
704     dy = MulDiv(ADVANCED_BUTTON_HEIGHT, PrefContext->MixerWindow->baseUnit.cy, 8);
705     if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
706         PrefContext->MixerWindow->rect.bottom += dy;
707 
708     /* now move the window */
709     AdjustWindowRect(&PrefContext->MixerWindow->rect, WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, TRUE);
710     SetWindowPos(PrefContext->MixerWindow->hWnd, HWND_TOP, PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.top, PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.bottom - PrefContext->MixerWindow->rect.top, SWP_NOMOVE | SWP_NOZORDER);
711 
712     /* Move the status bar */
713     if (PrefContext->MixerWindow->hStatusBar)
714     {
715         SetWindowPos(PrefContext->MixerWindow->hStatusBar,
716                      HWND_TOP,
717                      statusRect.left,
718                      PrefContext->MixerWindow->rect.bottom - (statusRect.bottom - statusRect.top),
719                      PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left,
720                      statusRect.bottom - statusRect.top,
721                      SWP_NOZORDER);
722     }
723 
724     if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
725         LoadStringW(hAppInstance, IDS_SELECT, szBuffer, ARRAYSIZE(szBuffer));
726 
727     for (i = 0; i < PrefContext->MixerWindow->DialogCount; i++)
728     {
729         if (PrefContext->MixerWindow->MixerId == RECORD_MIXER)
730         {
731             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SWITCH);
732 
733             /* Turn the autocheckbox into a checkbox */
734             SetWindowLongPtr(hDlgCtrl, GWL_STYLE, (GetWindowLongPtr(hDlgCtrl, GWL_STYLE) & ~BS_AUTOCHECKBOX) | BS_CHECKBOX);
735 
736             /* Change text from 'Mute' to 'Select' */
737             SetWindowTextW(hDlgCtrl, szBuffer);
738         }
739 
740         /* Resize the vertical line separator */
741         hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, (i + 1) * IDC_LINE_SEP);
742         if (hDlgCtrl != NULL)
743         {
744             GetWindowRect(hDlgCtrl, &statusRect);
745             if (PrefContext->MixerWindow->bShowExtendedControls && PrefContext->MixerWindow->bHasExtendedControls)
746                 statusRect.bottom += dy;
747 
748             SetWindowPos(hDlgCtrl,
749                          HWND_TOP,
750                          0,
751                          0,
752                          statusRect.right - statusRect.left,
753                          statusRect.bottom - statusRect.top,
754                          SWP_NOMOVE | SWP_NOZORDER);
755         }
756     }
757 
758     /* Hide the last line separator */
759     hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->MixerWindow->DialogCount);
760     if (hDlgCtrl != NULL)
761     {
762         ShowWindow(hDlgCtrl, SW_HIDE);
763     }
764 }
765 
766 VOID
767 UpdateDialogLineSwitchControl(
768     PPREFERENCES_CONTEXT PrefContext,
769     LPMIXERLINE Line,
770     LONG fValue)
771 {
772     DWORD Index;
773     DWORD wID;
774     HWND hDlgCtrl;
775     WCHAR LineName[MIXER_LONG_NAME_CHARS];
776 
777     /* find the index of this line */
778     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
779     {
780         /* get id */
781         wID = (Index + 1) * IDC_LINE_NAME;
782 
783         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
784         {
785             /* failed to retrieve id */
786             continue;
787         }
788 
789         /* check if the line name matches */
790         if (!wcsicmp(LineName, Line->szName))
791         {
792             /* found matching line name */
793             wID = (Index + 1) * IDC_LINE_SWITCH;
794 
795             /* get dialog control */
796             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
797 
798             if (hDlgCtrl != NULL)
799             {
800                 /* check state */
801                 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != fValue)
802                 {
803                     /* update control state */
804                     SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)fValue, 0);
805                 }
806             }
807             break;
808         }
809     }
810 }
811 
812 VOID
813 UpdateDialogLineSliderControl(
814     PPREFERENCES_CONTEXT PrefContext,
815     LPMIXERLINE Line,
816     DWORD dwDialogID,
817     DWORD Position)
818 {
819     DWORD Index;
820     DWORD wID;
821     HWND hDlgCtrl;
822     WCHAR LineName[MIXER_LONG_NAME_CHARS];
823 
824     /* find the index of this line */
825     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
826     {
827         /* get id */
828         wID = (Index + 1) * IDC_LINE_NAME;
829 
830         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
831         {
832             /* failed to retrieve id */
833             continue;
834         }
835 
836         /* check if the line name matches */
837         if (!wcsicmp(LineName, Line->szName))
838         {
839             /* found matching line name */
840             wID = (Index + 1) * dwDialogID;
841 
842             /* get dialog control */
843             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
844 
845             if (hDlgCtrl != NULL)
846             {
847                 /* check state */
848                 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
849                 if (OldPosition != Position)
850                 {
851                     /* update control state */
852                     SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position);
853                 }
854             }
855             break;
856         }
857     }
858 }
859