Leaked source code of windows server 2003
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.

425 lines
17 KiB

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