xref: /reactos/dll/cpl/mmsys/mmsys.c (revision 34593d93)
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 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             swprintf(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     swprintf(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             swprintf(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()
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", (wcslen(L".Default")+1) * sizeof(WCHAR));
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     TCHAR ClassName[50];
374     int Result = 0;
375     HMODULE hModule = NULL;
376     UpdateDriverForPlugAndPlayDevicesProto UpdateProc;
377     BOOL reboot = FALSE;
378     DWORD flags = 0;
379 
380     if (!SetupDiGetINFClass(InfPath,&ClassGUID,ClassName,sizeof(ClassName)/sizeof(ClassName[0]),0))
381     {
382         return -1;
383     }
384 
385     DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID,0);
386     if(DeviceInfoSet == INVALID_HANDLE_VALUE)
387     {
388         return -1;
389     }
390 
391     DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
392     if (!SetupDiCreateDeviceInfo(DeviceInfoSet, ClassName, &ClassGUID, NULL, 0, DICD_GENERATE_ID, &DeviceInfoData))
393     {
394         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
395         return -1;
396     }
397 
398     if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (LPBYTE)HardwareIdList, (lstrlen(HardwareIdList)+1+1)*sizeof(TCHAR)))
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(GetFileAttributes(InfPath)==(DWORD)(-1)) {
411         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
412         return -1;
413     }
414 
415     flags |= INSTALLFLAG_FORCE;
416     hModule = LoadLibraryW(L"newdev.dll");
417     if(!hModule) {
418         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
419         return -1;
420     }
421 
422     UpdateProc = (UpdateDriverForPlugAndPlayDevicesProto)GetProcAddress(hModule,UPDATEDRIVERFORPLUGANDPLAYDEVICES);
423     if(!UpdateProc)
424     {
425         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
426         FreeLibrary(hModule);
427         return -1;
428     }
429 
430     if(!UpdateProc(NULL, HardwareIdList, InfPath, flags, &reboot))
431     {
432         SetupDiDestroyDeviceInfoList(DeviceInfoSet);
433         FreeLibrary(hModule);
434         return -1;
435     }
436 
437     FreeLibrary(hModule);
438     SetupDiDestroyDeviceInfoList(DeviceInfoSet);
439     return Result;
440 }
441 
442 DWORD
443 MMSYS_InstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
444 {
445     UINT Length;
446     LPWSTR pBuffer;
447     WCHAR szBuffer[MAX_PATH];
448     HINF hInf;
449     PVOID Context;
450     BOOL Result;
451     SC_HANDLE hSCManager, hService;
452     WCHAR WaveName[20];
453     HKEY hKey;
454     DWORD BufferSize;
455     ULONG Index;
456 
457     if (!IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_SOUND) &&
458         !IsEqualIID(&pspDevInfoData->ClassGuid, &GUID_DEVCLASS_MEDIA))
459         return ERROR_DI_DO_DEFAULT;
460 
461     Length = GetWindowsDirectoryW(szBuffer, MAX_PATH);
462     if (!Length || Length >= MAX_PATH - 14)
463     {
464         return ERROR_GEN_FAILURE;
465     }
466 
467     pBuffer = PathAddBackslashW(szBuffer);
468     if (!pBuffer)
469     {
470         return ERROR_GEN_FAILURE;
471     }
472 
473     wcscpy(pBuffer, L"inf\\audio.inf");
474 
475     hInf = SetupOpenInfFileW(szBuffer,
476                              NULL,
477                             INF_STYLE_WIN4,
478                             NULL);
479 
480     if (hInf == INVALID_HANDLE_VALUE)
481     {
482         return ERROR_GEN_FAILURE;
483     }
484 
485     Context = SetupInitDefaultQueueCallback(NULL);
486     if (Context == NULL)
487     {
488         SetupCloseInfFile(hInf);
489         return ERROR_GEN_FAILURE;
490     }
491 
492     Result = SetupInstallFromInfSectionW(NULL,
493                                          hInf,
494                                          L"AUDIO_Inst.NT",
495                                          SPINST_ALL,
496                                          NULL,
497                                          NULL,
498                                          SP_COPY_NEWER,
499                                          SetupDefaultQueueCallbackW,
500                                          Context,
501                                          NULL,
502                                          NULL);
503 
504     if (Result)
505     {
506         Result = SetupInstallServicesFromInfSectionW(hInf,
507                                                      L"Audio_Inst.NT.Services",
508                                                      0);
509     }
510 
511     SetupTermDefaultQueueCallback(Context);
512     SetupCloseInfFile(hInf);
513 
514     if (!IsSoftwareBusPnpEnumeratorInstalled())
515     {
516         Length = GetWindowsDirectoryW(szBuffer, MAX_PATH);
517         if (!Length || Length >= MAX_PATH - 14)
518         {
519             return ERROR_GEN_FAILURE;
520         }
521 
522         pBuffer = PathAddBackslashW(szBuffer);
523         if (!pBuffer)
524         {
525             return ERROR_GEN_FAILURE;
526         }
527 
528         wcscpy(pBuffer, L"inf\\machine.inf");
529         InstallSoftwareBusPnpEnumerator(szBuffer, L"ROOT\\SWENUM\0");
530     }
531 
532     hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
533     if (!hSCManager)
534     {
535         return ERROR_DI_DO_DEFAULT;
536     }
537 
538     hService = OpenService(hSCManager, L"AudioSrv", SERVICE_ALL_ACCESS);
539     if (hService)
540     {
541         /* Make AudioSrv start automatically */
542         ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
543 
544         StartService(hService, 0, NULL);
545         CloseServiceHandle(hService);
546     }
547     CloseServiceHandle(hSCManager);
548 
549     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", 0, GENERIC_READ | GENERIC_WRITE, &hKey) == ERROR_SUCCESS)
550     {
551         szBuffer[Length] = '\0';
552         pBuffer = PathAddBackslashW(szBuffer);
553         wcscpy(pBuffer, L"system32\\wdmaud.drv");
554 
555         for(Index = 1; Index <= 4; Index++)
556         {
557             swprintf(WaveName, L"wave%u", Index);
558             if (RegQueryValueExW(hKey, WaveName, 0, NULL, NULL, &BufferSize) != ERROR_MORE_DATA)
559             {
560                 /* Store new audio driver entry */
561                 RegSetValueExW(hKey, WaveName, 0, REG_SZ, (LPBYTE)szBuffer, (wcslen(szBuffer)+1) * sizeof(WCHAR));
562                 break;
563             }
564             else
565             {
566                 WCHAR Buffer[MAX_PATH];
567                 BufferSize = sizeof(Buffer);
568 
569                 if (RegQueryValueExW(hKey, WaveName, 0, NULL, (LPBYTE)Buffer, &BufferSize) == ERROR_SUCCESS)
570                 {
571                     /* Make sure the buffer is zero terminated */
572                     Buffer[MAX_PATH-1] = L'\0';
573 
574                     if (!wcsicmp(Buffer, szBuffer))
575                     {
576                         /* An entry already exists */
577                         break;
578                     }
579                 }
580             }
581         }
582         RegCloseKey(hKey);
583     }
584     InstallSystemSoundScheme();
585 
586     return ERROR_DI_DO_DEFAULT;
587 
588 }
589 
590 DWORD
591 MMSYS_RemoveDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
592 {
593     return ERROR_DI_DO_DEFAULT;
594 }
595 
596 DWORD
597 MMSYS_AllowInstallDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
598 {
599     return ERROR_DI_DO_DEFAULT;
600 }
601 
602 DWORD
603 MMSYS_SelectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
604 {
605     return ERROR_DI_DO_DEFAULT;
606 }
607 
608 DWORD
609 MMSYS_DetectDevice(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
610 {
611     return ERROR_DI_DO_DEFAULT;
612 }
613 
614 DWORD
615 MMSYS_SelectBestCompatDRV(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pspDevInfoData)
616 {
617     return ERROR_DI_DO_DEFAULT;
618 }
619 
620 DWORD WINAPI
621 MediaClassInstaller(IN DI_FUNCTION diFunction,
622                     IN HDEVINFO hDevInfo,
623                     IN PSP_DEVINFO_DATA pspDevInfoData OPTIONAL)
624 {
625     switch (diFunction)
626     {
627         case DIF_INSTALLDEVICE:
628             return MMSYS_InstallDevice(hDevInfo, pspDevInfoData);
629         case DIF_REMOVE:
630             return MMSYS_RemoveDevice(hDevInfo, pspDevInfoData);
631         case DIF_ALLOW_INSTALL:
632             return MMSYS_AllowInstallDevice(hDevInfo, pspDevInfoData);
633         case DIF_SELECTDEVICE:
634             return MMSYS_SelectDevice(hDevInfo, pspDevInfoData);
635         case DIF_DETECT:
636             return MMSYS_DetectDevice(hDevInfo, pspDevInfoData);
637         case DIF_SELECTBESTCOMPATDRV:
638             return MMSYS_SelectBestCompatDRV(hDevInfo, pspDevInfoData);
639         default:
640             return ERROR_DI_DO_DEFAULT;
641     }
642 }
643 
644 
645 /* Hardware property page dialog callback */
646 static INT_PTR CALLBACK
647 HardwareDlgProc(HWND hwndDlg,
648                 UINT uMsg,
649                 WPARAM wParam,
650                 LPARAM lParam)
651 {
652     UNREFERENCED_PARAMETER(lParam);
653     UNREFERENCED_PARAMETER(wParam);
654     switch(uMsg)
655     {
656         case WM_INITDIALOG:
657         {
658             GUID Guids[2];
659             Guids[0] = GUID_DEVCLASS_CDROM;
660             Guids[1] = GUID_DEVCLASS_MEDIA;
661 
662             /* Create the hardware page */
663             DeviceCreateHardwarePageEx(hwndDlg,
664                                        Guids,
665                                        sizeof(Guids) / sizeof(Guids[0]),
666                                        HWPD_LARGELIST);
667             break;
668         }
669     }
670 
671     return FALSE;
672 }
673 
674 static int CALLBACK
675 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
676 {
677     // NOTE: This callback is needed to set large icon correctly.
678     HICON hIcon;
679     switch (uMsg)
680     {
681         case PSCB_INITIALIZED:
682         {
683             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDI_CPLICON));
684             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
685             break;
686         }
687     }
688     return 0;
689 }
690 
691 LONG APIENTRY
692 MmSysApplet(HWND hwnd,
693             UINT uMsg,
694             LPARAM wParam,
695             LPARAM lParam)
696 {
697     PROPSHEETPAGE psp[5];
698     PROPSHEETHEADER psh; // = { 0 };
699     TCHAR Caption[256];
700     INT nPage = 0;
701 
702     UNREFERENCED_PARAMETER(lParam);
703     UNREFERENCED_PARAMETER(wParam);
704     UNREFERENCED_PARAMETER(uMsg);
705 
706     if (uMsg == CPL_STARTWPARMSW && lParam != 0)
707         nPage = _wtoi((PWSTR)lParam);
708 
709     LoadString(hApplet, IDS_CPLNAME, Caption, _countof(Caption));
710 
711     psh.dwSize = sizeof(PROPSHEETHEADER);
712     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
713     psh.hwndParent = hwnd;
714     psh.hInstance = hApplet;
715     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
716     psh.pszCaption = Caption;
717     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
718     psh.nStartPage = 0;
719     psh.ppsp = psp;
720     psh.pfnCallback = PropSheetProc;
721 
722     InitPropSheetPage(&psp[0], IDD_VOLUME,VolumeDlgProc);
723     InitPropSheetPage(&psp[1], IDD_SOUNDS,SoundsDlgProc);
724     InitPropSheetPage(&psp[2], IDD_AUDIO,AudioDlgProc);
725     InitPropSheetPage(&psp[3], IDD_VOICE,VoiceDlgProc);
726     InitPropSheetPage(&psp[4], IDD_HARDWARE,HardwareDlgProc);
727 
728     if (nPage != 0 && nPage <= psh.nPages)
729         psh.nStartPage = nPage;
730 
731     return (LONG)(PropertySheet(&psh) != -1);
732 }
733 
734 VOID
735 InitPropSheetPage(PROPSHEETPAGE *psp,
736                   WORD idDlg,
737                   DLGPROC DlgProc)
738 {
739     ZeroMemory(psp, sizeof(PROPSHEETPAGE));
740     psp->dwSize = sizeof(PROPSHEETPAGE);
741     psp->dwFlags = PSP_DEFAULT;
742     psp->hInstance = hApplet;
743     psp->pszTemplate = MAKEINTRESOURCE(idDlg);
744     psp->pfnDlgProc = DlgProc;
745 }
746 
747 
748 /* Control Panel Callback */
749 LONG CALLBACK
750 CPlApplet(HWND hwndCpl,
751           UINT uMsg,
752           LPARAM lParam1,
753           LPARAM lParam2)
754 {
755     switch(uMsg)
756     {
757         case CPL_INIT:
758             return TRUE;
759 
760         case CPL_GETCOUNT:
761             return NUM_APPLETS;
762 
763         case CPL_INQUIRE:
764         {
765             CPLINFO *CPlInfo = (CPLINFO*)lParam2;
766             UINT uAppIndex = (UINT)lParam1;
767 
768             CPlInfo->lData = 0;
769             CPlInfo->idIcon = Applets[uAppIndex].idIcon;
770             CPlInfo->idName = Applets[uAppIndex].idName;
771             CPlInfo->idInfo = Applets[uAppIndex].idDescription;
772             break;
773         }
774 
775         case CPL_DBLCLK:
776         {
777             UINT uAppIndex = (UINT)lParam1;
778             Applets[uAppIndex].AppletProc(hwndCpl,
779                                           uMsg,
780                                           lParam1,
781                                           lParam2);
782             break;
783         }
784 
785         case CPL_STARTWPARMSW:
786             return Applets[(UINT)lParam1].AppletProc(hwndCpl, uMsg, lParam1, lParam2);
787     }
788 
789     return FALSE;
790 }
791 
792 VOID WINAPI
793 ShowAudioPropertySheet(HWND hwnd,
794                        HINSTANCE hInstance,
795                        LPTSTR lpszCmd,
796                        int nCmdShow)
797 {
798     PROPSHEETPAGE psp[1];
799     PROPSHEETHEADER psh;
800     TCHAR Caption[256];
801 
802     DPRINT("ShowAudioPropertySheet()\n");
803 
804     LoadString(hApplet, IDS_CPLNAME, Caption, _countof(Caption));
805 
806     psh.dwSize = sizeof(PROPSHEETHEADER);
807     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
808     psh.hwndParent = hwnd;
809     psh.hInstance = hInstance;
810     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
811     psh.pszCaption = Caption;
812     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
813     psh.nStartPage = 0;
814     psh.ppsp = psp;
815     psh.pfnCallback = PropSheetProc;
816 
817     InitPropSheetPage(&psp[0], IDD_AUDIO,AudioDlgProc);
818 
819     PropertySheet(&psh);
820 }
821 
822 VOID WINAPI
823 ShowFullControlPanel(HWND hwnd,
824                      HINSTANCE hInstance,
825                      LPSTR lpszCmd,
826                      int nCmdShow)
827 {
828     PROPSHEETPAGE psp[5];
829     PROPSHEETHEADER psh;
830     TCHAR Caption[256];
831 
832     DPRINT("ShowFullControlPanel()\n");
833 
834     LoadString(hApplet, IDS_CPLNAME, Caption, _countof(Caption));
835 
836     psh.dwSize = sizeof(PROPSHEETHEADER);
837     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
838     psh.hwndParent = hwnd;
839     psh.hInstance = hInstance;
840     psh.pszIcon = MAKEINTRESOURCEW(IDI_CPLICON);
841     psh.pszCaption = Caption;
842     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
843     psh.nStartPage = 0;
844     psh.ppsp = psp;
845     psh.pfnCallback = PropSheetProc;
846 
847     InitPropSheetPage(&psp[0], IDD_VOLUME,VolumeDlgProc);
848     InitPropSheetPage(&psp[1], IDD_SOUNDS,SoundsDlgProc);
849     InitPropSheetPage(&psp[2], IDD_AUDIO,AudioDlgProc);
850     InitPropSheetPage(&psp[3], IDD_VOICE,VoiceDlgProc);
851     InitPropSheetPage(&psp[4], IDD_HARDWARE,HardwareDlgProc);
852 
853     PropertySheet(&psh);
854 }
855 
856 BOOL WINAPI
857 DllMain(HINSTANCE hinstDLL,
858         DWORD dwReason,
859         LPVOID lpReserved)
860 {
861     UNREFERENCED_PARAMETER(lpReserved);
862     switch(dwReason)
863     {
864         case DLL_PROCESS_ATTACH:
865             hApplet = hinstDLL;
866             DisableThreadLibraryCalls(hinstDLL);
867             break;
868     }
869 
870     return TRUE;
871 }
872