Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
15 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. //---------------------------------------------------------------------------
  4. #include "control.h"
  5. #include <cpl.h>
  6. #include <cplp.h>
  7. #include <shlwapi.h>
  8. #include <shlwapip.h>
  9. #include "rcids.h"
  10. BOOL ImmDisableIME(DWORD dwThreadId);
  11. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  12. // LEAVE THESE IN ENGLISH
  13. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  14. const TCHAR c_szCtlPanelClass[] = TEXT("CtlPanelClass");
  15. const TCHAR c_szExplorer[] = TEXT("explorer.exe");
  16. const TCHAR c_szRunDLL32[] = TEXT("rundll32.exe");
  17. const TCHAR c_szRunDLLShell32Etc[] = TEXT("Shell32.dll,Control_RunDLL ");
  18. const TCHAR c_szControlPanelFolder[] =
  19. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\"");
  20. const TCHAR c_szDoPrinters[] =
  21. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}\"");
  22. const TCHAR c_szDoFonts[] =
  23. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D20EA4E1-3957-11d2-A40B-0C5020524152}\"");
  24. const TCHAR c_szDoAdminTools[] =
  25. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D20EA4E1-3957-11d2-A40B-0C5020524153}\"");
  26. const TCHAR c_szDoSchedTasks[] =
  27. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D6277990-4C6A-11CF-8D87-00AA0060F5BF}\"");
  28. const TCHAR c_szDoNetConnections[] =
  29. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\"");
  30. const TCHAR c_szDoNetplwizUsers[] =
  31. TEXT("netplwiz.dll,UsersRunDll");
  32. const TCHAR c_szDoFolderOptions[] =
  33. TEXT("shell32.dll,Options_RunDLL 0");
  34. const TCHAR c_szDoScannerCamera[] =
  35. TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{E211B736-43FD-11D1-9EFB-0000F8757FCD}\"");
  36. typedef struct
  37. {
  38. LPCTSTR szOldForm;
  39. DWORD dwOS;
  40. LPCTSTR szFile;
  41. LPCTSTR szParameters;
  42. } COMPATCPL;
  43. #define OS_ANY ((DWORD)-1)
  44. COMPATCPL const c_aCompatCpls[] =
  45. {
  46. { TEXT("DESKTOP"), OS_ANY, TEXT("desk.cpl"), NULL },
  47. { TEXT("COLOR"), OS_ANY, TEXT("desk.cpl"), TEXT(",2") },
  48. { TEXT("DATE/TIME"), OS_ANY, TEXT("timedate.cpl"), NULL },
  49. { TEXT("PORTS"), OS_ANY, TEXT("sysdm.cpl"), TEXT(",1") },
  50. { TEXT("INTERNATIONAL"), OS_ANY, TEXT("intl.cpl"), NULL },
  51. { TEXT("MOUSE"), OS_ANY, TEXT("main.cpl"), NULL },
  52. { TEXT("KEYBOARD"), OS_ANY, TEXT("main.cpl"), TEXT("@1") },
  53. { TEXT("NETWARE"), OS_ANY, TEXT("nwc.cpl"), NULL },
  54. { TEXT("TELEPHONY"), OS_ANY, TEXT("telephon.cpl"), NULL },
  55. { TEXT("INFRARED"), OS_ANY, TEXT("irprops.cpl"), NULL },
  56. { TEXT("USERPASSWORDS"), OS_ANYSERVER, TEXT("lusrmgr.msc"), NULL },
  57. { TEXT("USERPASSWORDS"), OS_WHISTLERORGREATER, TEXT("nusrmgr.cpl"), NULL },
  58. { TEXT("USERPASSWORDS2"), OS_ANY, c_szRunDLL32, c_szDoNetplwizUsers },
  59. { TEXT("PRINTERS"), OS_ANY, c_szExplorer, c_szDoPrinters },
  60. { TEXT("FONTS"), OS_ANY, c_szExplorer, c_szDoFonts },
  61. { TEXT("ADMINTOOLS"), OS_ANY, c_szExplorer, c_szDoAdminTools },
  62. { TEXT("SCHEDTASKS"), OS_ANY, c_szExplorer, c_szDoSchedTasks },
  63. { TEXT("NETCONNECTIONS"), OS_ANY, c_szExplorer, c_szDoNetConnections },
  64. { TEXT("FOLDERS"), OS_ANY, c_szRunDLL32, c_szDoFolderOptions },
  65. { TEXT("SCANNERCAMERA"), OS_ANY, c_szExplorer, c_szDoScannerCamera },
  66. { TEXT("STICPL.CPL"), OS_ANY, c_szExplorer, c_szDoScannerCamera },
  67. };
  68. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  69. // Timer
  70. #define TIMER_QUITNOW 1
  71. #define TIMEOUT 10000
  72. #define DM_CPTRACE 0
  73. DWORD GetRegisteredCplPath(LPCTSTR pszNameIn, LPTSTR pszPathOut, UINT cchPathOut)
  74. {
  75. const HKEY rghkeyRoot[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
  76. const TCHAR szSubkey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
  77. DWORD dwResult = ERROR_INSUFFICIENT_BUFFER;
  78. if (0 < cchPathOut)
  79. {
  80. int i;
  81. *pszPathOut = TEXT('\0');
  82. for (i = 0; i < ARRAYSIZE(rghkeyRoot) && TEXT('\0') == *pszPathOut; i++)
  83. {
  84. HKEY hkey;
  85. dwResult = RegOpenKeyEx(rghkeyRoot[i],
  86. szSubkey,
  87. 0,
  88. KEY_QUERY_VALUE,
  89. &hkey);
  90. if (ERROR_SUCCESS == dwResult)
  91. {
  92. TCHAR szName[MAX_PATH]; // Destination for value name.
  93. TCHAR szPath[MAX_PATH * 2]; // Destination for value data.
  94. DWORD dwIndex = 0;
  95. DWORD cbPath;
  96. DWORD cchName;
  97. DWORD dwType;
  98. do
  99. {
  100. cchName = ARRAYSIZE(szName);
  101. cbPath = sizeof(szPath);
  102. dwResult = RegEnumValue(hkey,
  103. dwIndex++,
  104. szName,
  105. &cchName,
  106. NULL,
  107. &dwType,
  108. (LPBYTE)szPath,
  109. &cbPath);
  110. if (ERROR_SUCCESS == dwResult && sizeof(TCHAR) < cbPath)
  111. {
  112. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
  113. {
  114. if (0 == lstrcmpi(pszNameIn, szName))
  115. {
  116. //
  117. // We have a match. Expand the path if necessary.
  118. //
  119. TCHAR szExpanded[ARRAYSIZE(szPath)];
  120. DWORD cchExpanded = ExpandEnvironmentStrings(szPath, szExpanded, ARRAYSIZE(szExpanded));
  121. //
  122. // Account for adding enclosing double quotes. Needed
  123. // in case path contains embedded spaces.
  124. //
  125. if (cchExpanded && ((cchExpanded + 2) < cchPathOut))
  126. {
  127. wsprintf(pszPathOut, TEXT("\"%s\""), szExpanded);
  128. }
  129. }
  130. }
  131. else
  132. {
  133. //
  134. // Invalid data type. Someone has hacked the registry.
  135. // Continue searching.
  136. //
  137. }
  138. }
  139. }
  140. while(ERROR_SUCCESS == dwResult && TEXT('\0') == *pszPathOut);
  141. RegCloseKey(hkey);
  142. }
  143. }
  144. }
  145. return dwResult;
  146. }
  147. //---------------------------------------------------------------------------
  148. LRESULT CALLBACK DummyControlPanelProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
  149. {
  150. switch (uMsg)
  151. {
  152. case WM_CREATE:
  153. DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Created..."));
  154. // We only want to hang around for a little while.
  155. SetTimer(hwnd, TIMER_QUITNOW, TIMEOUT, NULL);
  156. return 0;
  157. case WM_DESTROY:
  158. DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Destroyed..."));
  159. // Quit the app when this window goes away.
  160. PostQuitMessage(0);
  161. return 0;
  162. case WM_TIMER:
  163. DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Timer %d"), wparam);
  164. if (wparam == TIMER_QUITNOW)
  165. {
  166. // Get this window to go away.
  167. DestroyWindow(hwnd);
  168. }
  169. return 0;
  170. case WM_COMMAND:
  171. DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Command %d"), wparam);
  172. // NB Hack for hollywood - they send a menu command to try
  173. // and open the printers applet. They try to search control panels
  174. // menu for the printers item and then post the associated command.
  175. // As our fake window doesn't have a menu they can't find the item
  176. // and post us a -1 instead (ripping on the way).
  177. if (wparam == (WPARAM)-1)
  178. {
  179. SHELLEXECUTEINFO sei = {0};
  180. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  181. sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_WAITFORINPUTIDLE;
  182. sei.lpFile = c_szExplorer;
  183. sei.lpParameters = c_szDoPrinters;
  184. sei.nShow = SW_SHOWNORMAL;
  185. ShellExecuteEx(&sei);
  186. }
  187. return 0;
  188. default:
  189. DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: %x %x %x %x"), hwnd, uMsg, wparam, lparam);
  190. return DefWindowProc(hwnd, uMsg, wparam, lparam);
  191. }
  192. }
  193. //---------------------------------------------------------------------------
  194. HWND _CreateDummyControlPanel(HINSTANCE hinst)
  195. {
  196. WNDCLASS wc;
  197. wc.style = 0;
  198. wc.lpfnWndProc = DummyControlPanelProc;
  199. wc.cbClsExtra = 0;
  200. wc.cbWndExtra = 0;
  201. wc.hInstance = hinst;
  202. wc.hIcon = NULL;
  203. wc.hCursor = NULL;
  204. wc.hbrBackground = NULL;
  205. wc.lpszMenuName = NULL;
  206. wc.lpszClassName = c_szCtlPanelClass;
  207. RegisterClass(&wc);
  208. return CreateWindow(c_szCtlPanelClass, NULL, 0, 0, 0, 0, 0, NULL, NULL, hinst, NULL);
  209. }
  210. void ProcessPolicy(void)
  211. {
  212. HINSTANCE hInst;
  213. APPLET_PROC pfnCPLApplet;
  214. hInst = LoadLibrary (TEXT("desk.cpl"));
  215. if (!hInst) {
  216. return;
  217. }
  218. pfnCPLApplet = (APPLET_PROC) GetProcAddress (hInst, "CPlApplet");
  219. if (pfnCPLApplet) {
  220. (*pfnCPLApplet)(NULL, CPL_POLICYREFRESH, 0, 0);
  221. }
  222. FreeLibrary (hInst);
  223. }
  224. //---------------------------------------------------------------------------
  225. int WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
  226. {
  227. SHELLEXECUTEINFO sei = {0};
  228. TCHAR szParameters[MAX_PATH * 2];
  229. MSG msg;
  230. HWND hwndDummy;
  231. DebugMsg(DM_TRACE, TEXT("cp.wm: Control starting."));
  232. ImmDisableIME(0);
  233. hwndDummy = _CreateDummyControlPanel(hInstance);
  234. // we need to check for PANEL passed in as an arg. The run dialog
  235. // autocomplete shows "Control Panel" as a choice and we used to
  236. // interpret this as Control with panel as an arg. So if we have
  237. // panel as an arg then we do the same processing as when we have
  238. // "Control" only.
  239. if (*lpCmdLine && lstrcmpi(lpCmdLine, TEXT("PANEL")))
  240. {
  241. int i;
  242. //
  243. // Policy hook. Userenv.dll will call control.exe with the
  244. // /policy command line switch. If so, we need to load the
  245. // desk.cpl applet and refresh the colors / bitmap.
  246. //
  247. if (lstrcmpi(TEXT("/policy"), lpCmdLine) == 0) {
  248. ProcessPolicy();
  249. return TRUE;
  250. }
  251. //
  252. // COMPAT HACK: special case some applets since apps depend on them
  253. //
  254. for (i = 0; !sei.lpFile && i < ARRAYSIZE(c_aCompatCpls); i++)
  255. {
  256. COMPATCPL const * pItem = &c_aCompatCpls[i];
  257. if (lstrcmpi(pItem->szOldForm, lpCmdLine) == 0
  258. && (pItem->dwOS == OS_ANY || IsOS(pItem->dwOS)))
  259. {
  260. sei.lpFile = pItem->szFile;
  261. sei.lpParameters = pItem->szParameters;
  262. }
  263. }
  264. if (!sei.lpFile)
  265. {
  266. int cch;
  267. //
  268. // Not a special-case CPL.
  269. // See if it's registered under "Control Panel\Cpls".
  270. // If so, we use the registered path.
  271. //
  272. lstrcpy(szParameters, c_szRunDLLShell32Etc);
  273. cch = lstrlen(szParameters);
  274. sei.lpFile = c_szRunDLL32;
  275. sei.lpParameters = szParameters;
  276. if (ERROR_SUCCESS != GetRegisteredCplPath(lpCmdLine,
  277. szParameters + cch,
  278. ARRAYSIZE(szParameters) - cch))
  279. {
  280. //
  281. // Not registered. Pass command line through.
  282. //
  283. lstrcpyn(szParameters + cch, lpCmdLine, ARRAYSIZE(szParameters) - cch);
  284. }
  285. }
  286. }
  287. else
  288. {
  289. // Open the Control Panel folder
  290. sei.lpFile = c_szExplorer;
  291. sei.lpParameters = c_szControlPanelFolder;
  292. }
  293. // HACK: NerdPerfect tries to open a hidden control panel to talk to
  294. // we are blowing off fixing the communication stuff so just make
  295. // sure the folder does not appear hidden
  296. if (nCmdShow == SW_HIDE)
  297. nCmdShow = SW_SHOWNORMAL;
  298. sei.cbSize = sizeof(sei);
  299. sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_WAITFORINPUTIDLE;
  300. sei.nShow = nCmdShow;
  301. ShellExecuteEx(&sei);
  302. if (IsWindow(hwndDummy))
  303. {
  304. while (GetMessage(&msg, NULL, 0, 0))
  305. {
  306. DispatchMessage(&msg);
  307. }
  308. }
  309. DebugMsg(DM_TRACE, TEXT("cp.wm: Control exiting."));
  310. return TRUE;
  311. }
  312. #ifdef WIN32
  313. //---------------------------------------------------------------------------
  314. // Stolen from the CRT, used to shrink our code.
  315. int _stdcall ModuleEntry(void)
  316. {
  317. STARTUPINFO si;
  318. LPTSTR pszCmdLine = GetCommandLine();
  319. if ( *pszCmdLine == TEXT('\"') ) {
  320. /*
  321. * Scan, and skip over, subsequent characters until
  322. * another double-quote or a null is encountered.
  323. */
  324. while ( *++pszCmdLine && (*pszCmdLine
  325. != TEXT('\"')) );
  326. /*
  327. * If we stopped on a double-quote (usual case), skip
  328. * over it.
  329. */
  330. if ( *pszCmdLine == TEXT('\"') )
  331. pszCmdLine++;
  332. }
  333. else {
  334. while (*pszCmdLine > TEXT(' '))
  335. pszCmdLine++;
  336. }
  337. /*
  338. * Skip past any white space preceeding the second token.
  339. */
  340. while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
  341. pszCmdLine++;
  342. }
  343. si.dwFlags = 0;
  344. GetStartupInfo(&si);
  345. ExitProcess(WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
  346. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT));
  347. return 0;
  348. }
  349. #endif