xref: /reactos/base/applications/control/control.c (revision 177ae91b)
1 /*
2  * PROJECT:     ReactOS System Control Panel
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     ReactOS System Control Panel
5  * COPYRIGHT:   Copyright 2004 Gero Kuehn (reactos.filter@gkware.com)
6  *              Copyright 2008 Colin Finck (colin@reactos.org)
7  *              Copyright 2014 Herm�s B�lusca-Ma�to (hermes.belusca-maito@reactos.org)
8  */
9 
10 #include <stdio.h>
11 
12 #define WIN32_NO_STATUS
13 
14 #include <windef.h>
15 #include <winbase.h>
16 #include <winuser.h>
17 #include <winreg.h>
18 #include <shellapi.h>
19 #include <strsafe.h>
20 
21 #include "resource.h"
22 
23 #define MAX_VALUE_NAME 16383
24 
25 /*
26  * Macro for calling "rundll32.exe"
27  * According to MSDN, ShellExecute returns a value greater than 32
28  * if the operation was successful.
29  */
30 #define RUNDLL(param)   \
31     ((INT_PTR)ShellExecuteW(NULL, L"open", L"rundll32.exe", (param), NULL, SW_SHOWDEFAULT) > 32)
32 
33 VOID
34 WINAPI
35 Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
36 
37 static INT
38 OpenShellFolder(LPWSTR lpFolderCLSID)
39 {
40     WCHAR szParameters[MAX_PATH];
41 
42     /*
43      * Open a shell folder using "explorer.exe". The passed CLSIDs
44      * are all subfolders of the "Control Panel" shell folder.
45      */
46     StringCbCopyW(szParameters, sizeof(szParameters), L"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}");
47     StringCbCatW(szParameters, sizeof(szParameters), lpFolderCLSID);
48 
49     return (INT_PTR)ShellExecuteW(NULL,
50                                   L"open",
51                                   L"explorer.exe",
52                                   szParameters,
53                                   NULL,
54                                   SW_SHOWDEFAULT) > 32;
55 }
56 
57 static INT
58 RunControlPanel(LPCWSTR lpCmd)
59 {
60     /*
61      * Old method:
62      *
63     WCHAR szParameters[MAX_PATH];
64     wcscpy(szParameters, L"shell32.dll,Control_RunDLL ");
65     wcscat(szParameters, lpCmd);
66     return RUNDLL(szParameters);
67      */
68 
69     /* New method: */
70     Control_RunDLLW(GetDesktopWindow(), 0, lpCmd, SW_SHOW);
71     return 1;
72 }
73 
74 INT
75 WINAPI
76 wWinMain(HINSTANCE hInstance,
77          HINSTANCE hPrevInstance,
78          LPWSTR lpCmdLine,
79          INT nCmdShow)
80 {
81     HKEY hKey;
82 
83     /* Show the control panel window if no argument or "panel" was passed */
84     if (*lpCmdLine == 0 || !_wcsicmp(lpCmdLine, L"panel"))
85         return OpenShellFolder(L"");
86 
87     /* Check one of the built-in control panel handlers */
88     if (!_wcsicmp(lpCmdLine, L"admintools"))           return OpenShellFolder(L"\\::{D20EA4E1-3957-11d2-A40B-0C5020524153}");
89     else if (!_wcsicmp(lpCmdLine, L"color"))           return RunControlPanel(L"desk.cpl,,2");
90     else if (!_wcsicmp(lpCmdLine, L"date/time"))       return RunControlPanel(L"timedate.cpl");
91     else if (!_wcsicmp(lpCmdLine, L"desktop"))         return RunControlPanel(L"desk.cpl");
92     else if (!_wcsicmp(lpCmdLine, L"folders"))         return RUNDLL(L"shell32.dll,Options_RunDLL");
93     else if (!_wcsicmp(lpCmdLine, L"fonts"))           return OpenShellFolder(L"\\::{D20EA4E1-3957-11d2-A40B-0C5020524152}");
94     else if (!_wcsicmp(lpCmdLine, L"infrared"))        return RunControlPanel(L"irprops.cpl");
95     else if (!_wcsicmp(lpCmdLine, L"international"))   return RunControlPanel(L"intl.cpl");
96     else if (!_wcsicmp(lpCmdLine, L"keyboard"))        return RunControlPanel(L"main.cpl @1");
97     else if (!_wcsicmp(lpCmdLine, L"mouse"))           return RunControlPanel(L"main.cpl @0");
98     else if (!_wcsicmp(lpCmdLine, L"netconnections"))  return OpenShellFolder(L"\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}");
99     else if (!_wcsicmp(lpCmdLine, L"netware"))         return RunControlPanel(L"nwc.cpl");
100     else if (!_wcsicmp(lpCmdLine, L"ports"))           return RunControlPanel(L"sysdm.cpl,,1");
101     else if (!_wcsicmp(lpCmdLine, L"printers"))        return OpenShellFolder(L"\\::{2227A280-3AEA-1069-A2DE-08002B30309D}");
102     else if (!_wcsicmp(lpCmdLine, L"scannercamera"))   return OpenShellFolder(L"\\::{E211B736-43FD-11D1-9EFB-0000F8757FCD}");
103     else if (!_wcsicmp(lpCmdLine, L"schedtasks"))      return OpenShellFolder(L"\\::{D6277990-4C6A-11CF-8D87-00AA0060F5BF}");
104     else if (!_wcsicmp(lpCmdLine, L"telephony"))       return RunControlPanel(L"telephon.cpl");
105     else if (!_wcsicmp(lpCmdLine, L"userpasswords"))   return RunControlPanel(L"nusrmgr.cpl");       /* Graphical User Account Manager */
106     else if (!_wcsicmp(lpCmdLine, L"userpasswords2"))  return RUNDLL(L"netplwiz.dll,UsersRunDll");   /* Dialog based advanced User Account Manager */
107 
108     /* It is none of them, so look for a handler in the registry */
109     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
110                       L"Software\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls",
111                       0,
112                       KEY_QUERY_VALUE,
113                       &hKey) == ERROR_SUCCESS)
114     {
115         DWORD dwIndex;
116 
117         for (dwIndex = 0; ; ++dwIndex)
118         {
119             DWORD dwDataSize;
120             DWORD dwValueSize = MAX_VALUE_NAME;
121             WCHAR szValueName[MAX_VALUE_NAME];
122 
123             /* Get the value name and data size */
124             if (RegEnumValueW(hKey,
125                               dwIndex,
126                               szValueName,
127                               &dwValueSize,
128                               0,
129                               NULL,
130                               NULL,
131                               &dwDataSize) != ERROR_SUCCESS)
132             {
133                 break;
134             }
135 
136             /* Check if the parameter is the value name */
137             if (!_wcsicmp(lpCmdLine, szValueName))
138             {
139                 /*
140                  * Allocate memory for the data plus two more characters,
141                  * so we can quote the file name if required.
142                  */
143                 LPWSTR pszData;
144                 pszData = HeapAlloc(GetProcessHeap(),
145                                     0,
146                                     dwDataSize + 2 * sizeof(WCHAR));
147                 ++pszData;
148 
149                 /*
150                  * This value is the one we are looking for, so get the data.
151                  * It is the path to a .cpl file.
152                  */
153                 if (RegQueryValueExW(hKey,
154                                      szValueName,
155                                      0,
156                                      NULL,
157                                      (LPBYTE)pszData,
158                                      &dwDataSize) == ERROR_SUCCESS)
159                 {
160                     INT nReturnValue;
161 
162                     /* Quote the file name if required */
163                     if (*pszData != L'\"')
164                     {
165                         *(--pszData) = L'\"';
166                         pszData[dwDataSize / sizeof(WCHAR)] = L'\"';
167                         pszData[(dwDataSize / sizeof(WCHAR)) + 1] = 0;
168                     }
169 
170                     nReturnValue = RunControlPanel(pszData);
171                     HeapFree(GetProcessHeap(), 0, pszData);
172                     RegCloseKey(hKey);
173 
174                     return nReturnValue;
175                 }
176 
177                 HeapFree(GetProcessHeap(), 0, pszData);
178             }
179         }
180 
181         RegCloseKey(hKey);
182     }
183 
184     /*
185      * It's none of the known parameters, so interpret the parameter
186      * as the file name of a control panel applet.
187      */
188     return RunControlPanel(lpCmdLine);
189 }
190