xref: /reactos/dll/cpl/mmsys/mmsys.c (revision cdf90707)
1 /*
2  *
3  * PROJECT:         ReactOS Multimedia Control Panel
4  * FILE:            dll/cpl/mmsys/mmsys.c
5  * PURPOSE:         ReactOS Multimedia Control Panel
6  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
7  *                  Dmitry Chapyshev <dmitry@reactos.org>
8  * UPDATE HISTORY:
9  *      2005/11/23  Created
10  */
11 
12 #include "mmsys.h"
13 
14 #include <winsvc.h>
15 #include <shlwapi.h>
16 #include <debug.h>
17 
18 #include <swenum.h>
19 #include <newdev.h>
20 #include <initguid.h>
21 #include <devguid.h>
22 
23 typedef enum
24 {
25     HWPD_STANDARDLIST = 0,
26     HWPD_LARGELIST,
27     HWPD_MAX = HWPD_LARGELIST
28 } HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
29 
30 typedef struct
31 {
32     LPWSTR LabelName;
33     LPWSTR DefaultName;
34     UINT LocalizedResId;
35     LPWSTR FileName;
36 } EVENT_LABEL_ITEM;
37 
38 typedef struct
39 {
40     LPWSTR LabelName;
41     LPWSTR DefaultName;
42     UINT IconId;
43 } SYSTEM_SCHEME_ITEM;
44 
45 static EVENT_LABEL_ITEM EventLabels[] =
46 {
47     {
48         L"WindowsLogon",
49         L"ReactOS Logon",
50         IDS_REACTOS_LOGON,
51         L"ReactOS_Logon.wav"
52     },
53     {
54         L"WindowsLogoff",
55         L"ReactOS Logoff",
56         IDS_REACTOS_LOGOFF,
57         L"ReactOS_Logoff.wav"
58     },
59     {
60         NULL,
61         NULL,
62         0,
63         NULL
64     }
65 };
66 
67 static SYSTEM_SCHEME_ITEM SystemSchemes[] =
68 {
69     {
70         L".Default",
71         L"ReactOS Standard",
72         IDS_REACTOS_DEFAULT_SCHEME
73     },
74     {
75         L".None",
76         L"No Sounds",
77         -1
78     },
79     {
80         NULL,
81         NULL
82     }
83 };
84 
85 
86 HWND WINAPI
87 DeviceCreateHardwarePageEx(HWND hWndParent,
88                            LPGUID lpGuids,
89                            UINT uNumberOfGuids,
90                            HWPAGE_DISPLAYMODE DisplayMode);
91 
92 typedef BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesProto)(
93     _In_opt_ HWND hwndParent,
94     _In_ LPCWSTR HardwareId,
95     _In_ LPCWSTR FullInfPath,
96     _In_ DWORD InstallFlags,
97     _Out_opt_ PBOOL bRebootRequired);
98 
99 #define UPDATEDRIVERFORPLUGANDPLAYDEVICES "UpdateDriverForPlugAndPlayDevicesW"
100 #define NUM_APPLETS    (1)
101 
102 
103 HINSTANCE hApplet = 0;
104 
105 /* Applets */
106 const APPLET Applets[NUM_APPLETS] =
107 {
108     {IDI_CPLICON, IDS_CPLNAME, IDS_CPLDESCRIPTION, MmSysApplet},
109 };
110 
111 
112 HRESULT WINAPI
113 DllCanUnloadNow(VOID)
114 {
115     DPRINT1("DllCanUnloadNow() stubs\n");
116     return S_OK;
117 }
118 
119 HRESULT WINAPI
120 DllGetClassObject(REFCLSID rclsid,
121                   REFIID riid,
122                   LPVOID *ppv)
123 {
124     DPRINT1("DllGetClassObject() stubs\n");
125     return S_OK;
126 }
127 
128 
129 VOID WINAPI
130 ShowDriverSettingsAfterForkW(HWND hwnd,
131                              HINSTANCE hInstance,
132                              LPWSTR lpszCmd,
133                              int nCmdShow)
134 {
135     DPRINT1("ShowDriverSettingsAfterForkW() stubs\n");
136 }
137 
138 VOID WINAPI
139 ShowDriverSettingsAfterForkA(HWND hwnd,
140                              HINSTANCE hInstance,
141                              LPSTR lpszCmd,
142                              int nCmdShow)
143 {
144     DPRINT1("ShowDriverSettingsAfterForkA() stubs\n");
145 }
146 
147 VOID WINAPI
148 ShowDriverSettingsAfterFork(HWND hwnd,
149                             HINSTANCE hInstance,
150                             LPSTR lpszCmd,
151                             int nCmdShow)
152 {
153     DPRINT1("ShowDriverSettingsAfterFork() stubs\n");
154 }
155 
156 BOOL WINAPI
157 ShowMMCPLPropertySheet(HWND hwnd,
158                        LPCSTR pszPropSheet,
159                        LPSTR pszName,
160                        LPSTR pszCaption)
161 {
162     DPRINT1("ShowMMCPLPropertySheet() stubs\n");
163     return TRUE;
164 }
165 
166 VOID WINAPI
167 mmseRunOnceW(HWND hwnd,
168              HINSTANCE hInstance,
169              LPWSTR lpszCmd,
170              int nCmdShow)
171 {
172     DPRINT1("mmseRunOnceW() stubs\n");
173 }
174 
175 VOID WINAPI
176 mmseRunOnceA(HWND hwnd,
177              HINSTANCE hInstance,
178              LPSTR lpszCmd,
179              int nCmdShow)
180 {
181     DPRINT1("mmseRunOnceA() stubs\n");
182 }
183 
184 VOID WINAPI
185 mmseRunOnce(HWND hwnd,
186             HINSTANCE hInstance,
187             LPSTR lpszCmd,
188             int nCmdShow)
189 {
190     DPRINT1("mmseRunOnce() stubs\n");
191 }
192 
193 BOOL WINAPI
194 MediaPropPageProvider(LPVOID Info,
195                       LPFNADDPROPSHEETPAGE PropSheetPage,
196                       LPARAM lParam)
197 {
198     DPRINT1("MediaPropPageProvider() stubs\n");
199     return TRUE;
200 }
201 
202 VOID
203 InstallSystemSoundLabels(HKEY hKey)
204 {
205     UINT i = 0;
206     HKEY hSubKey;
207     WCHAR Buffer[40];
208 
209     do
210     {
211         if (RegCreateKeyExW(hKey, EventLabels[i].LabelName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
212         {
213             RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)EventLabels[i].DefaultName, (wcslen(EventLabels[i].DefaultName) + 1) * sizeof(WCHAR));
214             StringCchPrintfW(Buffer, _countof(Buffer), L"@mmsys.cpl,-%u", EventLabels[i].LocalizedResId);
215             RegSetValueExW(hSubKey, L"DispFileName", 0, REG_SZ, (LPBYTE)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
216 
217             RegCloseKey(hSubKey);
218         }
219         i++;
220     } while (EventLabels[i].LabelName);
221 }
222 
223 VOID
224 InstallSystemSoundSchemeNames(HKEY hKey)
225 {
226     UINT i = 0;
227     HKEY hSubKey;
228 
229     do
230     {
231         if (RegCreateKeyExW(hKey, SystemSchemes[i].LabelName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
232         {
233             RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)SystemSchemes[i].DefaultName, (wcslen(SystemSchemes[i].DefaultName) + 1) * sizeof(WCHAR));
234             RegCloseKey(hSubKey);
235         }
236         i++;
237     } while (SystemSchemes[i].LabelName);
238 }
239 
240 VOID
241 InstallDefaultSystemSoundScheme(HKEY hRootKey)
242 {
243     HKEY hKey, hSubKey;
244     WCHAR Path[MAX_PATH];
245     UINT i = 0;
246 
247     if (RegCreateKeyExW(hRootKey, L".Default", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS)
248         return;
249 
250     RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)SystemSchemes[0].DefaultName, (wcslen(SystemSchemes[0].DefaultName) + 1) * sizeof(WCHAR));
251     StringCchPrintfW(Path, _countof(Path), L"@mmsys.cpl,-%u", SystemSchemes[0].IconId);
252     RegSetValueExW(hKey, L"DispFileName", 0, REG_SZ, (LPBYTE)Path, (wcslen(Path) + 1) * sizeof(WCHAR));
253 
254     do
255     {
256         if (RegCreateKeyExW(hKey, EventLabels[i].LabelName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
257         {
258             HKEY hScheme;
259 
260             StringCchPrintfW(Path, _countof(Path), L"%%SystemRoot%%\\media\\%s", EventLabels[i].FileName);
261             if (RegCreateKeyExW(hSubKey, L".Current", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hScheme, NULL) == ERROR_SUCCESS)
262             {
263                 RegSetValueExW(hScheme, NULL, 0, REG_EXPAND_SZ, (LPBYTE)Path, (wcslen(Path) + 1) * sizeof(WCHAR));
264                 RegCloseKey(hScheme);
265             }
266 
267             if (RegCreateKeyExW(hSubKey, L".Default", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hScheme, NULL) == ERROR_SUCCESS)
268             {
269                 RegSetValueExW(hScheme, NULL, 0, REG_EXPAND_SZ, (LPBYTE)Path, (wcslen(Path) + 1) * sizeof(WCHAR));
270                 RegCloseKey(hScheme);
271             }
272             RegCloseKey(hSubKey);
273         }
274         i++;
275     } while (EventLabels[i].LabelName);
276 
277     RegCloseKey(hKey);
278 }
279 
280 
281 VOID
282 InstallSystemSoundScheme(VOID)
283 {
284     HKEY hKey, hSubKey;
285     DWORD dwDisposition;
286 
287     if (RegCreateKeyExW(HKEY_CURRENT_USER, L"AppEvents", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS)
288         return;
289 
290     if (RegCreateKeyExW(hKey, L"EventLabels", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
291     {
292         InstallSystemSoundLabels(hSubKey);
293         RegCloseKey(hSubKey);
294     }
295 
296     if (RegCreateKeyExW(hKey, L"Schemes", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, &dwDisposition) == ERROR_SUCCESS)
297     {
298         HKEY hNames;
299 
300         if (RegCreateKeyExW(hSubKey, L"Names", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNames, NULL) == ERROR_SUCCESS)
301         {
302             InstallSystemSoundSchemeNames(hNames);
303             RegCloseKey(hNames);
304         }
305 
306         if (RegCreateKeyExW(hSubKey, L"Apps", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNames, NULL) == ERROR_SUCCESS)
307         {
308             InstallDefaultSystemSoundScheme(hNames);
309             RegCloseKey(hNames);
310             if (dwDisposition & REG_CREATED_NEW_KEY)
311             {
312                 // FIXME
313                 RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)L".Default", sizeof(L".Default"));
314             }
315         }
316 
317         RegCloseKey(hSubKey);
318     }
319 
320     RegCloseKey(hKey);
321 }
322 
323 BOOL
324 IsSoftwareBusPnpEnumeratorInstalled()
325 {
326     HDEVINFO hDevInfo;
327     SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
328     GUID SWBusGuid = {STATIC_BUSID_SoftwareDeviceEnumerator};
329     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData;
330 
331     hDevInfo = SetupDiGetClassDevsW(&SWBusGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
332     if (!hDevInfo)
333     {
334         // failed
335         return FALSE;
336     }
337 
338     DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
339     if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &SWBusGuid, 0, &DeviceInterfaceData))
340     {
341         // failed
342         SetupDiDestroyDeviceInfoList(hDevInfo);
343         return FALSE;
344     }
345 
346     DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, (MAX_PATH * sizeof(WCHAR)) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W));
347     if (!DeviceInterfaceDetailData)
348     {
349         // failed
350         SetupDiDestroyDeviceInfoList(hDevInfo);
351         return FALSE;
352     }
353 
354     DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
355     if (!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData, (MAX_PATH * sizeof(WCHAR)) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W), NULL, NULL))
356     {
357         // failed
358         HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
359         SetupDiDestroyDeviceInfoList(hDevInfo);
360         return FALSE;
361     }
362     HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
363     SetupDiDestroyDeviceInfoList(hDevInfo);
364     return TRUE;
365 }
366 
367 DWORD
368 InstallSoftwareBusPnpEnumerator(LPWSTR InfPath, LPCWSTR HardwareIdList)
369 {
370     HDEVINFO DeviceInfoSet = INVALID_HANDLE_VALUE;
371     SP_DEVINFO_DATA DeviceInfoData;
372     GUID ClassGUID;
373     WCHAR ClassName[50];
374     int Result = 0;
375     HMODULE hModule = NULL;
376     UpdateDriverForPlugAndPlayDevicesProto UpdateProc;
377     BOOL reboot = FALSE;
378     DWORD flags = 0;
379 
380     if (!SetupDiGetINFClassW(InfPath, &ClassGUID, ClassName, _countof(ClassName), NULL))
381     {
382         return -1;
383     }
384 
385     DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID, NULL);
386     if (DeviceInfoSet == INVALID_HANDLE_VALUE)
387     {
388         return -1;
389     }
390 
391     DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
392     if (!SetupDiCreateDeviceInfoW(DeviceInfoSet, ClassName, &ClassGUID, NULL, NULL, DICD_GENERATE_ID, &DeviceInfoData))
393     {
394         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
395         return -1;
396     }
397 
398     if (!SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (LPBYTE)HardwareIdList, (wcslen(HardwareIdList) + 1 + 1) * sizeof(WCHAR)))
399     {
400         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
401         return -1;
402     }
403 
404     if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DeviceInfoSet, &DeviceInfoData))
405     {
406         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
407         return -1;
408     }
409 
410     if (GetFileAttributesW(InfPath) == INVALID_FILE_ATTRIBUTES)
411     {
412         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
413         return -1;
414     }
415 
416     flags |= INSTALLFLAG_FORCE;
417     hModule = LoadLibraryW(L"newdev.dll");
418     if (!hModule)
419     {
420         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
421         return -1;
422     }
423 
424     UpdateProc = (UpdateDriverForPlugAndPlayDevicesProto)GetProcAddress(hModule, UPDATEDRIVERFORPLUGANDPLAYDEVICES);
425     if (!UpdateProc)
426     {
427         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
428         FreeLibrary(hModule);
429         return -1;
430     }
431 
432     if (!UpdateProc(NULL, HardwareIdList, InfPath, flags, &reboot))
433     {
434         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
435         FreeLibrary(hModule);
436         return -1;
437     }
438 
439     FreeLibrary(hModule);
440     SetupDiDestroyDeviceInfoList(DeviceInfoSet);
441     return Result;
442 }
443 
444 DWORD
445 MMSYS_InstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
446 {
447     UINT Length;
448     WCHAR szBuffer[MAX_PATH];
449     HINF hInf;
450     PVOID Context;
451     BOOL Result;
452     SC_HANDLE hSCManager, hService;
453     WCHAR WaveName[20];
454     HKEY hKey;
455     DWORD BufferSize;
456     ULONG Index;
457 
458     if (!IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_SOUND) &&
459         !IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_MEDIA))
460         return ERROR_DI_DO_DEFAULT;
461 
462     Length = GetWindowsDirectoryW(szBuffer, _countof(szBuffer));
463     if (!Length || Length >= _countof(szBuffer) - CONST_STR_LEN(L"\\inf\\audio.inf"))
464     {
465         return ERROR_GEN_FAILURE;
466     }
467 
468     //PathCchAppend(szBuffer, _countof(szBuffer), L"inf\\audio.inf");
469     StringCchCatW(szBuffer, _countof(szBuffer), L"\\inf\\audio.inf");
470 
471     hInf = SetupOpenInfFileW(szBuffer,
472                              NULL,
473                              INF_STYLE_WIN4,
474                              NULL);
475 
476     if (hInf == INVALID_HANDLE_VALUE)
477     {
478         return ERROR_GEN_FAILURE;
479     }
480 
481     Context = SetupInitDefaultQueueCallback(NULL);
482     if (Context == NULL)
483     {
484         SetupCloseInfFile(hInf);
485         return ERROR_GEN_FAILURE;
486     }
487 
488     Result = SetupInstallFromInfSectionW(NULL,
489                                          hInf,
490                                          L"AUDIO_Inst.NT",
491                                          SPINST_ALL,
492                                          NULL,
493                                          NULL,
494                                          SP_COPY_NEWER,
495                                          SetupDefaultQueueCallbackW,
496                                          Context,
497                                          NULL,
498                                          NULL);
499 
500     if (Result)
501     {
502         Result = SetupInstallServicesFromInfSectionW(hInf,
503                                                      L"Audio_Inst.NT.Services",
504                                                      0);
505     }
506 
507     SetupTermDefaultQueueCallback(Context);
508     SetupCloseInfFile(hInf);
509 
510     if (!IsSoftwareBusPnpEnumeratorInstalled())
511     {
512         Length = GetWindowsDirectoryW(szBuffer, _countof(szBuffer));
513         if (!Length || Length >= _countof(szBuffer) - CONST_STR_LEN(L"\\inf\\machine.inf"))
514         {
515             return ERROR_GEN_FAILURE;
516         }
517 
518         //PathCchAppend(szBuffer, _countof(szBuffer), L"inf\\machine.inf");
519         StringCchCatW(szBuffer, _countof(szBuffer), L"\\inf\\machine.inf");
520 
521         InstallSoftwareBusPnpEnumerator(szBuffer, L"ROOT\\SWENUM\0");
522     }
523 
524     hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
525     if (!hSCManager)
526     {
527         return ERROR_DI_DO_DEFAULT;
528     }
529 
530     hService = OpenServiceW(hSCManager, L"AudioSrv", SERVICE_ALL_ACCESS);
531     if (hService)
532     {
533         /* Make AudioSrv start automatically */
534         ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
535 
536         StartServiceW(hService, 0, NULL);
537         CloseServiceHandle(hService);
538     }
539     CloseServiceHandle(hSCManager);
540 
541     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS)
542     {
543         Length = GetSystemDirectoryW(szBuffer, _countof(szBuffer));
544         if (!Length || Length >= _countof(szBuffer) - CONST_STR_LEN(L"\\wdmaud.drv"))
545         {
546             RegCloseKey(hKey);
547             return ERROR_DI_DO_DEFAULT;
548         }
549 
550         //PathCchAppend(szBuffer, _countof(szBuffer), L"wdmaud.drv");
551         StringCchCatW(szBuffer, _countof(szBuffer), L"\\wdmaud.drv");
552 
553         for (Index = 1; Index <= 4; Index++)
554         {
555             StringCchPrintfW(WaveName, _countof(WaveName), L"wave%u", Index);
556             if (RegQueryValueExW(hKey, WaveName, 0, NULL, NULL, &BufferSize) != ERROR_MORE_DATA)
557             {
558                 /* Store new audio driver entry */
559                 RegSetValueExW(hKey, WaveName, 0, REG_SZ, (LPBYTE)szBuffer, (wcslen(szBuffer) + 1) * sizeof(WCHAR));
560                 break;
561             }
562             else
563             {
564                 WCHAR Buffer[MAX_PATH];
565                 BufferSize = sizeof(Buffer);
566 
567                 if (RegQueryValueExW(hKey, WaveName, 0, NULL, (LPBYTE)Buffer, &BufferSize) == ERROR_SUCCESS)
568                 {
569                     /* Make sure the buffer is zero terminated */
570                     Buffer[_countof(Buffer) - 1] = UNICODE_NULL;
571 
572                     if (!_wcsicmp(Buffer, szBuffer))
573                     {
574                         /* An entry already exists */
575                         break;
576                     }
577                 }
578             }
579         }
580         RegCloseKey(hKey);
581     }
582     InstallSystemSoundScheme();
583 
584     return ERROR_DI_DO_DEFAULT;
585 
586 }
587 
588 DWORD
589 MMSYS_RemoveDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
590 {
591     return ERROR_DI_DO_DEFAULT;
592 }
593 
594 DWORD
595 MMSYS_AllowInstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
596 {
597     return ERROR_DI_DO_DEFAULT;
598 }
599 
600 DWORD
601 MMSYS_SelectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
602 {
603     return ERROR_DI_DO_DEFAULT;
604 }
605 
606 DWORD
607 MMSYS_DetectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
608 {
609     return ERROR_DI_DO_DEFAULT;
610 }
611 
612 DWORD
613 MMSYS_SelectBestCompatDRV(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
614 {
615     return ERROR_DI_DO_DEFAULT;
616 }
617 
618 DWORD WINAPI
619 MediaClassInstaller(IN DI_FUNCTION diFunction,
620                     IN HDEVINFO hDevInfo,
621                     IN PSP_DEVINFO_DATA pspDevInfoData OPTIONAL)
622 {
623     switch (diFunction)
624     {
625         case DIF_INSTALLDEVICE:
626             return MMSYS_InstallDevice(hDevInfo, pspDevInfoData);
627         case DIF_REMOVE:
628             return MMSYS_RemoveDevice(hDevInfo, pspDevInfoData);
629         case DIF_ALLOW_INSTALL:
630             return MMSYS_AllowInstallDevice(hDevInfo, pspDevInfoData);
631         case DIF_SELECTDEVICE:
632             return MMSYS_SelectDevice(hDevInfo, pspDevInfoData);
633         case DIF_DETECT:
634             return MMSYS_DetectDevice(hDevInfo, pspDevInfoData);
635         case DIF_SELECTBESTCOMPATDRV:
636             return MMSYS_SelectBestCompatDRV(hDevInfo, pspDevInfoData);
637         default:
638             return ERROR_DI_DO_DEFAULT;
639     }
640 }
641 
642 
643 /* Hardware property page dialog callback */
644 static INT_PTR CALLBACK
645 HardwareDlgProc(HWND hwndDlg,
646                 UINT uMsg,
647                 WPARAM wParam,
648                 LPARAM lParam)
649 {
650     UNREFERENCED_PARAMETER(lParam);
651     UNREFERENCED_PARAMETER(wParam);
652     switch (uMsg)
653     {
654         case WM_INITDIALOG:
655         {
656             GUID Guids[2];
657             Guids[0] = GUID_DEVCLASS_CDROM;
658             Guids[1] = GUID_DEVCLASS_MEDIA;
659 
660             /* Create the hardware page */
661             DeviceCreateHardwarePageEx(hwndDlg,
662                                        Guids,
663                                        _countof(Guids),
664                                        HWPD_LARGELIST);
665             break;
666         }
667     }
668 
669     return FALSE;
670 }
671 
672 static int CALLBACK
673 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
674 {
675     // NOTE: This callback is needed to set large icon correctly.
676     HICON hIcon;
677     switch (uMsg)
678     {
679         case PSCB_INITIALIZED:
680         {
681             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDI_CPLICON));
682             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
683             break;
684         }
685     }
686     return 0;
687 }
688 
689 LONG APIENTRY
690 MmSysApplet(HWND hwnd,
691             UINT uMsg,
692             LPARAM wParam,
693             LPARAM lParam)
694 {
695     PROPSHEETPAGEW psp[5];
696     PROPSHEETHEADERW psh; // = { 0 };
697     INT nPage = 0;
698 
699     UNREFERENCED_PARAMETER(wParam);
700 
701     if (uMsg == CPL_STARTWPARMSW && lParam != 0)
702         nPage = _wtoi((PWSTR)lParam);
703 
704     psh.dwSize = sizeof(PROPSHEETHEADERW);
705     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
706     psh.hwndParent = hwnd;
707     psh.hInstance = hApplet;
708     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
709     psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME);
710     psh.nPages = _countof(psp);
711     psh.nStartPage = 0;
712     psh.ppsp = psp;
713     psh.pfnCallback = PropSheetProc;
714 
715     InitPropSheetPage(&psp[0], IDD_VOLUME, VolumeDlgProc);
716     InitPropSheetPage(&psp[1], IDD_SOUNDS, SoundsDlgProc);
717     InitPropSheetPage(&psp[2], IDD_AUDIO, AudioDlgProc);
718     InitPropSheetPage(&psp[3], IDD_VOICE, VoiceDlgProc);
719     InitPropSheetPage(&psp[4], IDD_HARDWARE, HardwareDlgProc);
720 
721     if (nPage != 0 && nPage <= psh.nPages)
722         psh.nStartPage = nPage;
723 
724     return (LONG)(PropertySheetW(&psh) != -1);
725 }
726 
727 VOID
728 InitPropSheetPage(PROPSHEETPAGEW *psp,
729                   WORD idDlg,
730                   DLGPROC DlgProc)
731 {
732     ZeroMemory(psp, sizeof(PROPSHEETPAGEW));
733     psp->dwSize = sizeof(PROPSHEETPAGEW);
734     psp->dwFlags = PSP_DEFAULT;
735     psp->hInstance = hApplet;
736     psp->pszTemplate = MAKEINTRESOURCEW(idDlg);
737     psp->pfnDlgProc = DlgProc;
738 }
739 
740 
741 /* Control Panel Callback */
742 LONG CALLBACK
743 CPlApplet(HWND hwndCpl,
744           UINT uMsg,
745           LPARAM lParam1,
746           LPARAM lParam2)
747 {
748     UINT i = (UINT)lParam1;
749 
750     switch (uMsg)
751     {
752         case CPL_INIT:
753             return TRUE;
754 
755         case CPL_GETCOUNT:
756             return NUM_APPLETS;
757 
758         case CPL_INQUIRE:
759             if (i < NUM_APPLETS)
760             {
761                 CPLINFO *CPlInfo = (CPLINFO*)lParam2;
762                 CPlInfo->lData = 0;
763                 CPlInfo->idIcon = Applets[i].idIcon;
764                 CPlInfo->idName = Applets[i].idName;
765                 CPlInfo->idInfo = Applets[i].idDescription;
766             }
767             else
768             {
769                 return TRUE;
770             }
771             break;
772 
773         case CPL_DBLCLK:
774             if (i < NUM_APPLETS)
775                 Applets[i].AppletProc(hwndCpl, uMsg, lParam1, lParam2);
776             else
777                 return TRUE;
778             break;
779 
780         case CPL_STARTWPARMSW:
781             if (i < NUM_APPLETS)
782                 return Applets[i].AppletProc(hwndCpl, uMsg, lParam1, lParam2);
783             break;
784     }
785 
786     return FALSE;
787 }
788 
789 VOID WINAPI
790 ShowAudioPropertySheet(HWND hwnd,
791                        HINSTANCE hInstance,
792                        LPWSTR lpszCmd,
793                        int nCmdShow)
794 {
795     PROPSHEETPAGEW psp[1];
796     PROPSHEETHEADERW psh;
797 
798     DPRINT("ShowAudioPropertySheet()\n");
799 
800     psh.dwSize = sizeof(PROPSHEETHEADERW);
801     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
802     psh.hwndParent = hwnd;
803     psh.hInstance = hInstance;
804     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
805     psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME);
806     psh.nPages = _countof(psp);
807     psh.nStartPage = 0;
808     psh.ppsp = psp;
809     psh.pfnCallback = PropSheetProc;
810 
811     InitPropSheetPage(&psp[0], IDD_AUDIO,AudioDlgProc);
812 
813     PropertySheetW(&psh);
814 }
815 
816 VOID WINAPI
817 ShowFullControlPanel(HWND hwnd,
818                      HINSTANCE hInstance,
819                      LPSTR lpszCmd,
820                      int nCmdShow)
821 {
822     PROPSHEETPAGEW psp[5];
823     PROPSHEETHEADERW psh;
824 
825     DPRINT("ShowFullControlPanel()\n");
826 
827     psh.dwSize = sizeof(PROPSHEETHEADERW);
828     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
829     psh.hwndParent = hwnd;
830     psh.hInstance = hInstance;
831     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
832     psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME);
833     psh.nPages = _countof(psp);
834     psh.nStartPage = 0;
835     psh.ppsp = psp;
836     psh.pfnCallback = PropSheetProc;
837 
838     InitPropSheetPage(&psp[0], IDD_VOLUME, VolumeDlgProc);
839     InitPropSheetPage(&psp[1], IDD_SOUNDS, SoundsDlgProc);
840     InitPropSheetPage(&psp[2], IDD_AUDIO, AudioDlgProc);
841     InitPropSheetPage(&psp[3], IDD_VOICE, VoiceDlgProc);
842     InitPropSheetPage(&psp[4], IDD_HARDWARE, HardwareDlgProc);
843 
844     PropertySheetW(&psh);
845 }
846 
847 BOOL WINAPI
848 DllMain(HINSTANCE hinstDLL,
849         DWORD dwReason,
850         LPVOID lpReserved)
851 {
852     UNREFERENCED_PARAMETER(lpReserved);
853     switch (dwReason)
854     {
855         case DLL_PROCESS_ATTACH:
856             hApplet = hinstDLL;
857             DisableThreadLibraryCalls(hinstDLL);
858             break;
859     }
860 
861     return TRUE;
862 }
863