xref: /reactos/dll/cpl/mmsys/mmsys.c (revision 62919904)
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)(IN OPTIONAL HWND hwndParent,
93                                                               IN LPCTSTR HardwareId,
94                                                               IN LPCTSTR FullInfPath,
95                                                               IN DWORD InstallFlags,
96                                                               OUT OPTIONAL PBOOL bRebootRequired
97                                                          );
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 ShowAudioPropertySheet(HWND hwnd,
168                        HINSTANCE hInstance,
169                        LPTSTR lpszCmd,
170                        int nCmdShow)
171 {
172     DPRINT1("ShowAudioPropertySheet() stubs\n");
173 }
174 
175 VOID WINAPI
176 mmseRunOnceW(HWND hwnd,
177              HINSTANCE hInstance,
178              LPWSTR lpszCmd,
179              int nCmdShow)
180 {
181     DPRINT1("mmseRunOnceW() stubs\n");
182 }
183 
184 VOID WINAPI
185 mmseRunOnceA(HWND hwnd,
186              HINSTANCE hInstance,
187              LPSTR lpszCmd,
188              int nCmdShow)
189 {
190     DPRINT1("mmseRunOnceA() stubs\n");
191 }
192 
193 VOID WINAPI
194 mmseRunOnce(HWND hwnd,
195             HINSTANCE hInstance,
196             LPSTR lpszCmd,
197             int nCmdShow)
198 {
199     DPRINT1("mmseRunOnce() stubs\n");
200 }
201 
202 BOOL WINAPI
203 MediaPropPageProvider(LPVOID Info,
204                       LPFNADDPROPSHEETPAGE PropSheetPage,
205                       LPARAM lParam)
206 {
207     DPRINT1("MediaPropPageProvider() stubs\n");
208     return TRUE;
209 }
210 
211 VOID WINAPI
212 ShowFullControlPanel(HWND hwnd,
213                      HINSTANCE hInstance,
214                      LPSTR lpszCmd,
215                      int nCmdShow)
216 {
217     DPRINT1("ShowFullControlPanel() stubs\n");
218 }
219 
220 VOID
221 InstallSystemSoundLabels(HKEY hKey)
222 {
223     UINT i = 0;
224     HKEY hSubKey;
225     WCHAR Buffer[40];
226 
227     do
228     {
229         if (RegCreateKeyExW(hKey, EventLabels[i].LabelName,  0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
230         {
231             RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)EventLabels[i].DefaultName, (wcslen(EventLabels[i].DefaultName)+1) * sizeof(WCHAR));
232             swprintf(Buffer, L"@mmsys.cpl,-%u", EventLabels[i].LocalizedResId);
233             RegSetValueExW(hSubKey, L"DispFileName", 0, REG_SZ, (LPBYTE)Buffer, (wcslen(Buffer)+1) * sizeof(WCHAR));
234 
235             RegCloseKey(hSubKey);
236         }
237         i++;
238     }while(EventLabels[i].LabelName);
239 }
240 
241 VOID
242 InstallSystemSoundSchemeNames(HKEY hKey)
243 {
244     UINT i = 0;
245     HKEY hSubKey;
246 
247     do
248     {
249         if (RegCreateKeyExW(hKey, SystemSchemes[i].LabelName,  0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
250         {
251             RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)SystemSchemes[i].DefaultName, (wcslen(SystemSchemes[i].DefaultName)+1) * sizeof(WCHAR));
252             RegCloseKey(hSubKey);
253         }
254         i++;
255     }while(SystemSchemes[i].LabelName);
256 }
257 
258 VOID
259 InstallDefaultSystemSoundScheme(HKEY hRootKey)
260 {
261     HKEY hKey, hSubKey;
262     WCHAR Path[MAX_PATH];
263     UINT i = 0;
264 
265     if (RegCreateKeyExW(hRootKey, L".Default", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS)
266         return;
267 
268     RegSetValueExW(hKey, NULL, 0, REG_SZ, (LPBYTE)SystemSchemes[0].DefaultName, (wcslen(SystemSchemes[0].DefaultName)+1) * sizeof(WCHAR));
269     swprintf(Path, L"@mmsys.cpl,-%u", SystemSchemes[0].IconId);
270     RegSetValueExW(hKey, L"DispFileName", 0, REG_SZ, (LPBYTE)Path, (wcslen(Path)+1) * sizeof(WCHAR));
271 
272     do
273     {
274         if (RegCreateKeyExW(hKey, EventLabels[i].LabelName,  0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
275         {
276             HKEY hScheme;
277 
278             swprintf(Path, L"%%SystemRoot%%\\media\\%s", EventLabels[i].FileName);
279             if (RegCreateKeyExW(hSubKey, L".Current",  0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hScheme, NULL) == ERROR_SUCCESS)
280             {
281                 RegSetValueExW(hScheme, NULL, 0, REG_EXPAND_SZ, (LPBYTE)Path, (wcslen(Path)+1) * sizeof(WCHAR));
282                 RegCloseKey(hScheme);
283             }
284 
285             if (RegCreateKeyExW(hSubKey, L".Default",  0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hScheme, NULL) == ERROR_SUCCESS)
286             {
287                 RegSetValueExW(hScheme, NULL, 0, REG_EXPAND_SZ, (LPBYTE)Path, (wcslen(Path)+1) * sizeof(WCHAR));
288                 RegCloseKey(hScheme);
289             }
290             RegCloseKey(hSubKey);
291         }
292         i++;
293     }while(EventLabels[i].LabelName);
294 
295     RegCloseKey(hKey);
296 }
297 
298 
299 VOID
300 InstallSystemSoundScheme()
301 {
302     HKEY hKey, hSubKey;
303     DWORD dwDisposition;
304 
305     if (RegCreateKeyExW(HKEY_CURRENT_USER, L"AppEvents", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS)
306         return;
307 
308     if (RegCreateKeyExW(hKey, L"EventLabels", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
309     {
310         InstallSystemSoundLabels(hSubKey);
311         RegCloseKey(hSubKey);
312     }
313 
314     if (RegCreateKeyExW(hKey, L"Schemes", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hSubKey, &dwDisposition) == ERROR_SUCCESS)
315     {
316         HKEY hNames;
317 
318         if (RegCreateKeyExW(hSubKey, L"Names", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNames, NULL) == ERROR_SUCCESS)
319         {
320             InstallSystemSoundSchemeNames(hNames);
321             RegCloseKey(hNames);
322         }
323 
324         if (RegCreateKeyExW(hSubKey, L"Apps", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hNames, NULL) == ERROR_SUCCESS)
325         {
326             InstallDefaultSystemSoundScheme(hNames);
327             RegCloseKey(hNames);
328             if (dwDisposition & REG_CREATED_NEW_KEY)
329             {
330                 // FIXME
331                 RegSetValueExW(hSubKey, NULL, 0, REG_SZ, (LPBYTE)L".Default", (wcslen(L".Default")+1) * sizeof(WCHAR));
332             }
333         }
334 
335         RegCloseKey(hSubKey);
336     }
337 
338     RegCloseKey(hKey);
339 }
340 
341 BOOL
342 IsSoftwareBusPnpEnumeratorInstalled()
343 {
344     HDEVINFO hDevInfo;
345     SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
346     GUID SWBusGuid = {STATIC_BUSID_SoftwareDeviceEnumerator};
347     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData;
348 
349     hDevInfo = SetupDiGetClassDevsW(&SWBusGuid, NULL, NULL,  DIGCF_DEVICEINTERFACE| DIGCF_PRESENT);
350     if (!hDevInfo)
351     {
352         // failed
353         return FALSE;
354     }
355 
356     DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
357     if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &SWBusGuid, 0, &DeviceInterfaceData))
358     {
359         // failed
360         SetupDiDestroyDeviceInfoList(hDevInfo);
361         return FALSE;
362     }
363 
364     DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W));
365     if (!DeviceInterfaceDetailData)
366     {
367         // failed
368         SetupDiDestroyDeviceInfoList(hDevInfo);
369         return FALSE;
370     }
371 
372     DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
373     if (!SetupDiGetDeviceInterfaceDetailW(hDevInfo,  &DeviceInterfaceData, DeviceInterfaceDetailData,MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W), NULL, NULL))
374     {
375         // failed
376         HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
377         SetupDiDestroyDeviceInfoList(hDevInfo);
378         return FALSE;
379     }
380     HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
381     SetupDiDestroyDeviceInfoList(hDevInfo);
382     return TRUE;
383 }
384 
385 DWORD
386 InstallSoftwareBusPnpEnumerator(LPWSTR InfPath, LPCWSTR HardwareIdList)
387 {
388     HDEVINFO DeviceInfoSet = INVALID_HANDLE_VALUE;
389     SP_DEVINFO_DATA DeviceInfoData;
390     GUID ClassGUID;
391     TCHAR ClassName[50];
392     int Result = 0;
393     HMODULE hModule = NULL;
394     UpdateDriverForPlugAndPlayDevicesProto UpdateProc;
395     BOOL reboot = FALSE;
396     DWORD flags = 0;
397 
398     if (!SetupDiGetINFClass(InfPath,&ClassGUID,ClassName,sizeof(ClassName)/sizeof(ClassName[0]),0))
399     {
400         return -1;
401     }
402 
403     DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID,0);
404     if(DeviceInfoSet == INVALID_HANDLE_VALUE)
405     {
406         return -1;
407     }
408 
409     DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
410     if (!SetupDiCreateDeviceInfo(DeviceInfoSet, ClassName, &ClassGUID, NULL, 0, DICD_GENERATE_ID, &DeviceInfoData))
411     {
412         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
413         return -1;
414     }
415 
416     if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (LPBYTE)HardwareIdList, (lstrlen(HardwareIdList)+1+1)*sizeof(TCHAR)))
417     {
418         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
419         return -1;
420     }
421 
422     if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DeviceInfoSet, &DeviceInfoData))
423     {
424         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
425         return -1;
426     }
427 
428     if(GetFileAttributes(InfPath)==(DWORD)(-1)) {
429         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
430         return -1;
431     }
432 
433     flags |= INSTALLFLAG_FORCE;
434     hModule = LoadLibraryW(L"newdev.dll");
435     if(!hModule) {
436         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
437         return -1;
438     }
439 
440     UpdateProc = (UpdateDriverForPlugAndPlayDevicesProto)GetProcAddress(hModule,UPDATEDRIVERFORPLUGANDPLAYDEVICES);
441     if(!UpdateProc)
442     {
443         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
444         FreeLibrary(hModule);
445         return -1;
446     }
447 
448     if(!UpdateProc(NULL, HardwareIdList, InfPath, flags, &reboot))
449     {
450         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
451         FreeLibrary(hModule);
452         return -1;
453     }
454 
455     FreeLibrary(hModule);
456     SetupDiDestroyDeviceInfoList(DeviceInfoSet);
457     return Result;
458 }
459 
460 DWORD
461 MMSYS_InstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
462 {
463     UINT Length;
464     LPWSTR pBuffer;
465     WCHAR szBuffer[MAX_PATH];
466     HINF hInf;
467     PVOID Context;
468     BOOL Result;
469     SC_HANDLE hSCManager, hService;
470     WCHAR WaveName[20];
471     HKEY hKey;
472     DWORD BufferSize;
473     ULONG Index;
474 
475     if (!IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_SOUND) &&
476         !IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_MEDIA))
477         return ERROR_DI_DO_DEFAULT;
478 
479     Length = GetWindowsDirectoryW(szBuffer, MAX_PATH);
480     if (!Length || Length >= MAX_PATH - 14)
481     {
482         return ERROR_GEN_FAILURE;
483     }
484 
485     pBuffer = PathAddBackslashW(szBuffer);
486     if (!pBuffer)
487     {
488         return ERROR_GEN_FAILURE;
489     }
490 
491     wcscpy(pBuffer, L"inf\\audio.inf");
492 
493     hInf = SetupOpenInfFileW(szBuffer,
494                              NULL,
495                             INF_STYLE_WIN4,
496                             NULL);
497 
498     if (hInf == INVALID_HANDLE_VALUE)
499     {
500         return ERROR_GEN_FAILURE;
501     }
502 
503     Context = SetupInitDefaultQueueCallback(NULL);
504     if (Context == NULL)
505     {
506         SetupCloseInfFile(hInf);
507         return ERROR_GEN_FAILURE;
508     }
509 
510     Result = SetupInstallFromInfSectionW(NULL,
511                                          hInf,
512                                          L"AUDIO_Inst.NT",
513                                          SPINST_ALL,
514                                          NULL,
515                                          NULL,
516                                          SP_COPY_NEWER,
517                                          SetupDefaultQueueCallbackW,
518                                          Context,
519                                          NULL,
520                                          NULL);
521 
522     if (Result)
523     {
524         Result = SetupInstallServicesFromInfSectionW(hInf,
525                                                      L"Audio_Inst.NT.Services",
526                                                      0);
527     }
528 
529     SetupTermDefaultQueueCallback(Context);
530     SetupCloseInfFile(hInf);
531 
532     if (!IsSoftwareBusPnpEnumeratorInstalled())
533     {
534         Length = GetWindowsDirectoryW(szBuffer, MAX_PATH);
535         if (!Length || Length >= MAX_PATH - 14)
536         {
537             return ERROR_GEN_FAILURE;
538         }
539 
540         pBuffer = PathAddBackslashW(szBuffer);
541         if (!pBuffer)
542         {
543             return ERROR_GEN_FAILURE;
544         }
545 
546         wcscpy(pBuffer, L"inf\\machine.inf");
547         InstallSoftwareBusPnpEnumerator(szBuffer, L"ROOT\\SWENUM\0");
548     }
549 
550     hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
551     if (!hSCManager)
552     {
553         return ERROR_DI_DO_DEFAULT;
554     }
555 
556     hService = OpenService(hSCManager, L"AudioSrv", SERVICE_ALL_ACCESS);
557     if (hService)
558     {
559         /* Make AudioSrv start automatically */
560         ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
561 
562         StartService(hService, 0, NULL);
563         CloseServiceHandle(hService);
564     }
565     CloseServiceHandle(hSCManager);
566 
567     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", 0, GENERIC_READ | GENERIC_WRITE, &hKey) == ERROR_SUCCESS)
568     {
569         szBuffer[Length] = '\0';
570         pBuffer = PathAddBackslashW(szBuffer);
571         wcscpy(pBuffer, L"system32\\wdmaud.drv");
572 
573         for(Index = 1; Index <= 4; Index++)
574         {
575             swprintf(WaveName, L"wave%u", Index);
576             if (RegQueryValueExW(hKey, WaveName, 0, NULL, NULL, &BufferSize) != ERROR_MORE_DATA)
577             {
578                 /* Store new audio driver entry */
579                 RegSetValueExW(hKey, WaveName, 0, REG_SZ, (LPBYTE)szBuffer, (wcslen(szBuffer)+1) * sizeof(WCHAR));
580                 break;
581             }
582             else
583             {
584                 WCHAR Buffer[MAX_PATH];
585                 BufferSize = sizeof(Buffer);
586 
587                 if (RegQueryValueExW(hKey, WaveName, 0, NULL, (LPBYTE)Buffer, &BufferSize) == ERROR_SUCCESS)
588                 {
589                     /* Make sure the buffer is zero terminated */
590                     Buffer[MAX_PATH-1] = L'\0';
591 
592                     if (!wcsicmp(Buffer, szBuffer))
593                     {
594                         /* An entry already exists */
595                         break;
596                     }
597                 }
598             }
599         }
600         RegCloseKey(hKey);
601     }
602     InstallSystemSoundScheme();
603 
604     return ERROR_DI_DO_DEFAULT;
605 
606 }
607 
608 DWORD
609 MMSYS_RemoveDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
610 {
611     return ERROR_DI_DO_DEFAULT;
612 }
613 
614 DWORD
615 MMSYS_AllowInstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
616 {
617     return ERROR_DI_DO_DEFAULT;
618 }
619 
620 DWORD
621 MMSYS_SelectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
622 {
623     return ERROR_DI_DO_DEFAULT;
624 }
625 
626 DWORD
627 MMSYS_DetectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
628 {
629     return ERROR_DI_DO_DEFAULT;
630 }
631 
632 DWORD
633 MMSYS_SelectBestCompatDRV(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
634 {
635     return ERROR_DI_DO_DEFAULT;
636 }
637 
638 DWORD WINAPI
639 MediaClassInstaller(IN DI_FUNCTION diFunction,
640                     IN HDEVINFO hDevInfo,
641                     IN PSP_DEVINFO_DATA pspDevInfoData OPTIONAL)
642 {
643     switch (diFunction)
644     {
645         case DIF_INSTALLDEVICE:
646             return MMSYS_InstallDevice(hDevInfo, pspDevInfoData);
647         case DIF_REMOVE:
648             return MMSYS_RemoveDevice(hDevInfo, pspDevInfoData);
649         case DIF_ALLOW_INSTALL:
650             return MMSYS_AllowInstallDevice(hDevInfo, pspDevInfoData);
651         case DIF_SELECTDEVICE:
652             return MMSYS_SelectDevice(hDevInfo, pspDevInfoData);
653         case DIF_DETECT:
654             return MMSYS_DetectDevice(hDevInfo, pspDevInfoData);
655         case DIF_SELECTBESTCOMPATDRV:
656             return MMSYS_SelectBestCompatDRV(hDevInfo, pspDevInfoData);
657         default:
658             return ERROR_DI_DO_DEFAULT;
659     }
660 }
661 
662 
663 /* Hardware property page dialog callback */
664 static INT_PTR CALLBACK
665 HardwareDlgProc(HWND hwndDlg,
666                 UINT uMsg,
667                 WPARAM wParam,
668                 LPARAM lParam)
669 {
670     UNREFERENCED_PARAMETER(lParam);
671     UNREFERENCED_PARAMETER(wParam);
672     switch(uMsg)
673     {
674         case WM_INITDIALOG:
675         {
676             GUID Guids[2];
677             Guids[0] = GUID_DEVCLASS_CDROM;
678             Guids[1] = GUID_DEVCLASS_MEDIA;
679 
680             /* Create the hardware page */
681             DeviceCreateHardwarePageEx(hwndDlg,
682                                        Guids,
683                                        sizeof(Guids) / sizeof(Guids[0]),
684                                        HWPD_LARGELIST);
685             break;
686         }
687     }
688 
689     return FALSE;
690 }
691 
692 static int CALLBACK
693 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
694 {
695     // NOTE: This callback is needed to set large icon correctly.
696     HICON hIcon;
697     switch (uMsg)
698     {
699         case PSCB_INITIALIZED:
700         {
701             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDI_CPLICON));
702             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
703             break;
704         }
705     }
706     return 0;
707 }
708 
709 LONG APIENTRY
710 MmSysApplet(HWND hwnd,
711             UINT uMsg,
712             LPARAM wParam,
713             LPARAM lParam)
714 {
715     PROPSHEETPAGE psp[5];
716     PROPSHEETHEADER psh; // = { 0 };
717     TCHAR Caption[256];
718 
719     UNREFERENCED_PARAMETER(lParam);
720     UNREFERENCED_PARAMETER(wParam);
721     UNREFERENCED_PARAMETER(uMsg);
722 
723     LoadString(hApplet, IDS_CPLNAME, Caption, _countof(Caption));
724 
725     psh.dwSize = sizeof(PROPSHEETHEADER);
726     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
727     psh.hwndParent = hwnd;
728     psh.hInstance = hApplet;
729     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
730     psh.pszCaption = Caption;
731     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
732     psh.nStartPage = 0;
733     psh.ppsp = psp;
734     psh.pfnCallback = PropSheetProc;
735 
736     InitPropSheetPage(&psp[0], IDD_VOLUME,VolumeDlgProc);
737     InitPropSheetPage(&psp[1], IDD_SOUNDS,SoundsDlgProc);
738     InitPropSheetPage(&psp[2], IDD_AUDIO,AudioDlgProc);
739     InitPropSheetPage(&psp[3], IDD_VOICE,VoiceDlgProc);
740     InitPropSheetPage(&psp[4], IDD_HARDWARE,HardwareDlgProc);
741 
742     return (LONG)(PropertySheet(&psh) != -1);
743 }
744 
745 VOID
746 InitPropSheetPage(PROPSHEETPAGE *psp,
747                   WORD idDlg,
748                   DLGPROC DlgProc)
749 {
750     ZeroMemory(psp, sizeof(PROPSHEETPAGE));
751     psp->dwSize = sizeof(PROPSHEETPAGE);
752     psp->dwFlags = PSP_DEFAULT;
753     psp->hInstance = hApplet;
754     psp->pszTemplate = MAKEINTRESOURCE(idDlg);
755     psp->pfnDlgProc = DlgProc;
756 }
757 
758 
759 /* Control Panel Callback */
760 LONG CALLBACK
761 CPlApplet(HWND hwndCpl,
762           UINT uMsg,
763           LPARAM lParam1,
764           LPARAM lParam2)
765 {
766     switch(uMsg)
767     {
768         case CPL_INIT:
769             return TRUE;
770 
771         case CPL_GETCOUNT:
772             return NUM_APPLETS;
773 
774         case CPL_INQUIRE:
775         {
776             CPLINFO *CPlInfo = (CPLINFO*)lParam2;
777             UINT uAppIndex = (UINT)lParam1;
778 
779             CPlInfo->lData = 0;
780             CPlInfo->idIcon = Applets[uAppIndex].idIcon;
781             CPlInfo->idName = Applets[uAppIndex].idName;
782             CPlInfo->idInfo = Applets[uAppIndex].idDescription;
783             break;
784         }
785 
786         case CPL_DBLCLK:
787         {
788             UINT uAppIndex = (UINT)lParam1;
789             Applets[uAppIndex].AppletProc(hwndCpl,
790                                           uMsg,
791                                           lParam1,
792                                           lParam2);
793             break;
794         }
795     }
796 
797     return FALSE;
798 }
799 
800 
801 BOOL WINAPI
802 DllMain(HINSTANCE hinstDLL,
803         DWORD dwReason,
804         LPVOID lpReserved)
805 {
806     UNREFERENCED_PARAMETER(lpReserved);
807     switch(dwReason)
808     {
809         case DLL_PROCESS_ATTACH:
810             hApplet = hinstDLL;
811             DisableThreadLibraryCalls(hinstDLL);
812             break;
813     }
814 
815     return TRUE;
816 }
817