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.

629 lines
16 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1996.
  5. //
  6. // File: taskwiz.cxx
  7. //
  8. // Contents: Class which creates and invokes the 'create new task' wizard.
  9. //
  10. // Classes: CTaskWizard
  11. //
  12. // History: 5-20-1997 DavidMun Created
  13. //
  14. //---------------------------------------------------------------------------
  15. #include "..\pch\headers.hxx"
  16. #pragma hdrstop
  17. #include "myheaders.hxx"
  18. #include "..\folderui\jobidl.hxx"
  19. //
  20. // Types
  21. //
  22. // SFindWiz - passed to window enumeration function. BUGBUG when wizard
  23. // on remote machine is supported, the 'tszFocus' member should be the
  24. // server name. For now, it is just the path to the tasks folder.
  25. //
  26. struct SFindWiz
  27. {
  28. BOOL fFound;
  29. LPCTSTR tszFocus;
  30. };
  31. //
  32. // Globals
  33. //
  34. // g_msgFindWizard - private window message used to interrogate the wizard
  35. // dialog proc during the find operation.
  36. //
  37. // TEMPLATE_STR - string used to create private message, also used by
  38. // folderui code to identify the template icon.
  39. //
  40. UINT g_msgFindWizard;
  41. extern const TCHAR TEMPLATE_STR[];
  42. //
  43. // External references
  44. //
  45. extern HRESULT
  46. QuietStartContinueService(); // ..\folderui\schstate.cxx
  47. extern HRESULT
  48. JFGetDataObject(
  49. LPCTSTR pszFolderPath,
  50. LPCITEMIDLIST pidlFolder,
  51. UINT cidl,
  52. LPCITEMIDLIST * apidl,
  53. BOOL fCut,
  54. LPVOID * ppvObj);
  55. extern HRESULT
  56. DisplayJobProperties(
  57. LPDATAOBJECT pdtobj);
  58. //+--------------------------------------------------------------------------
  59. //
  60. // Member: CTaskWizard::CTaskWizard
  61. //
  62. // Synopsis: ctor
  63. //
  64. // Arguments: [ptszFolderPath] - path to tasks folder
  65. //
  66. // History: 5-12-1997 DavidMun Created
  67. //
  68. //---------------------------------------------------------------------------
  69. CTaskWizard::CTaskWizard(
  70. LPCTSTR ptszFolderPath,
  71. LPITEMIDLIST pidlFolder)
  72. {
  73. TRACE_CONSTRUCTOR(CTaskWizard);
  74. ZeroMemory(_apWizPages, sizeof _apWizPages);
  75. _fAdvanced = FALSE;
  76. _tszJobObjectFullPath[0] = TEXT('\0');
  77. _pTask = NULL;
  78. lstrcpyn(_tszFolderPath, ptszFolderPath, ARRAYLEN(_tszFolderPath));
  79. _pidlFolder = pidlFolder;
  80. #ifdef WIZARD97
  81. _fUse256ColorBmp = Is256ColorSupported();
  82. #endif // WIZARD97
  83. }
  84. //+--------------------------------------------------------------------------
  85. //
  86. // Member: CTaskWizard::~CTaskWizard
  87. //
  88. // Synopsis: dtor
  89. //
  90. // History: 5-19-1997 DavidMun Created
  91. //
  92. //---------------------------------------------------------------------------
  93. CTaskWizard::~CTaskWizard()
  94. {
  95. TRACE_DESTRUCTOR(CTaskWizard);
  96. if (_pTask)
  97. {
  98. _pTask->Release();
  99. }
  100. ILFree(_pidlFolder);
  101. }
  102. //+--------------------------------------------------------------------------
  103. //
  104. // Member: CTaskWizard::Launch, static
  105. //
  106. // Synopsis: Run the task wizard in a separate thread.
  107. //
  108. // Arguments: [ptszFolderPath] - path to tasks folder.
  109. //
  110. // Returns: HRESULT
  111. //
  112. // History: 5-19-1997 DavidMun Created
  113. //
  114. // Notes: If an instance of the wizard is already running for the
  115. // target machine, makes that the foreground window and
  116. // returns.
  117. //
  118. //---------------------------------------------------------------------------
  119. HRESULT
  120. CTaskWizard::Launch(
  121. LPCTSTR ptszFolderPath,
  122. LPCITEMIDLIST pidlFolder)
  123. {
  124. TRACE_FUNCTION(CTaskWizard::Launch);
  125. HRESULT hr = S_OK;
  126. CTaskWizard *pNewWiz = NULL;
  127. do
  128. {
  129. //
  130. // Start the service if it isn't running, or continue it if it is
  131. // paused. Since this is the wizard, do it on behalf of the user
  132. // without asking first.
  133. //
  134. // Continue on failure, since it is better to let the user at least
  135. // create the task, even if the service can't be started (user might
  136. // not have permission).
  137. //
  138. hr = QuietStartContinueService();
  139. CHECK_HRESULT(hr);
  140. //
  141. // Create a path string that CPropPage will store. This is the
  142. // full path to the tasks folder, with a trailing backslash. The
  143. // CPropPage will truncate at the last backslash, since most other
  144. // callers give it a task filename.
  145. //
  146. ULONG cchPath = lstrlen(ptszFolderPath);
  147. if (cchPath >= MAX_PATH - 1) // reserve space for trailing backslash
  148. {
  149. hr = E_INVALIDARG;
  150. DEBUG_OUT_HRESULT(hr);
  151. break;
  152. }
  153. TCHAR tszFolderPath[MAX_PATH + 1];
  154. lstrcpy(tszFolderPath, ptszFolderPath);
  155. tszFolderPath[cchPath] = TEXT('\\');
  156. tszFolderPath[cchPath + 1] = TEXT('\0');
  157. //
  158. // Look for an instance of the wizard running and focused on our
  159. // folder path. If one is found, it will make itself foreground
  160. // window, and we can quit.
  161. //
  162. hr = _FindWizard(tszFolderPath);
  163. if (hr == S_OK)
  164. {
  165. break;
  166. }
  167. //
  168. // No wizard is up for the current focus. Create a wizard object
  169. // and run it in a new thread.
  170. //
  171. LPITEMIDLIST pidlFolderCopy = ILClone(pidlFolder);
  172. if (!pidlFolderCopy)
  173. {
  174. hr = E_OUTOFMEMORY;
  175. DEBUG_OUT_HRESULT(hr);
  176. break;
  177. }
  178. pNewWiz = new CTaskWizard(tszFolderPath, pidlFolderCopy);
  179. if (!pNewWiz)
  180. {
  181. ILFree(pidlFolderCopy);
  182. hr = E_OUTOFMEMORY;
  183. DEBUG_OUT_HRESULT(hr);
  184. break;
  185. }
  186. HANDLE hThread;
  187. DWORD idThread;
  188. hThread = CreateThread(NULL,
  189. 0,
  190. _WizardThreadProc,
  191. (LPVOID) pNewWiz,
  192. 0,
  193. &idThread);
  194. if (!hThread)
  195. {
  196. delete pNewWiz;
  197. DEBUG_OUT_LASTERROR;
  198. hr = HRESULT_FROM_LASTERROR;
  199. break;
  200. }
  201. VERIFY(CloseHandle(hThread));
  202. } while (0);
  203. return hr;
  204. }
  205. //+--------------------------------------------------------------------------
  206. //
  207. // Member: CTaskWizard::_WizardThreadProc, static
  208. //
  209. // Synopsis: Displays the wizard (and optionally task property sheet)
  210. // using a separate thread.
  211. //
  212. // Arguments: [pvThis] - CTaskWizard pointer
  213. //
  214. // Returns: HRESULT
  215. //
  216. // History: 5-20-1997 DavidMun Created
  217. //
  218. // Notes: The wizard runs in a separate thread so the explorer ui
  219. // isn't stalled.
  220. //
  221. //---------------------------------------------------------------------------
  222. DWORD WINAPI
  223. CTaskWizard::_WizardThreadProc(
  224. LPVOID pvThis)
  225. {
  226. HRESULT hr = OleInitialize(NULL);
  227. if (FAILED(hr))
  228. {
  229. DEBUG_OUT_HRESULT(hr);
  230. return hr;
  231. }
  232. CTaskWizard *pThis = (CTaskWizard *)pvThis;
  233. __try
  234. {
  235. hr = pThis->_DoWizard();
  236. //
  237. // Once _DoWizard returns, the wizard property sheet has closed.
  238. //
  239. // If the user elected to see the new task's property sheet, then
  240. // _fAdvanced will be set, and the completion page should have
  241. // set a valid filename and interface pointer for the task.
  242. //
  243. // Open the property sheet while we're still in the thread.
  244. //
  245. if (SUCCEEDED(hr) && pThis->_fAdvanced)
  246. {
  247. DEBUG_ASSERT(pThis->_pTask);
  248. DEBUG_ASSERT(*pThis->_tszJobObjectFullPath);
  249. //
  250. // Since we want to see the security page if the object is on NT
  251. // on an NTFS partition, we'll have to call the version of
  252. // DisplayJobProperties that takes a data object.
  253. //
  254. // To get a data object describing the task object, we need an
  255. // itemid for the job, so create one.
  256. //
  257. CJobID jid;
  258. jid.LoadDummy(pThis->_tszJobObjectFullPath);
  259. LPCITEMIDLIST pidl = (LPCITEMIDLIST) &jid;
  260. LPDATAOBJECT pdo = NULL;
  261. TCHAR tszFolderPath[MAX_PATH + 1];
  262. lstrcpy(tszFolderPath, pThis->_tszFolderPath);
  263. LPTSTR ptszLastSlash = _tcsrchr(tszFolderPath, TEXT('\\'));
  264. if (ptszLastSlash && lstrlen(ptszLastSlash) == 1)
  265. {
  266. *ptszLastSlash = TEXT('\0');
  267. }
  268. hr = JFGetDataObject(tszFolderPath, // path to tasks dir
  269. pThis->_pidlFolder, // itemid of tasks folder
  270. 1, // one itemid in array
  271. &pidl, // namely, this one
  272. FALSE, // not doing cut/paste
  273. (VOID **) &pdo);
  274. if (SUCCEEDED(hr))
  275. {
  276. hr = DisplayJobProperties(pdo);
  277. CHECK_HRESULT(hr);
  278. }
  279. else
  280. {
  281. DEBUG_OUT_HRESULT(hr);
  282. }
  283. }
  284. delete pThis;
  285. }
  286. __finally
  287. {
  288. OleUninitialize();
  289. }
  290. return (DWORD) hr;
  291. }
  292. //+--------------------------------------------------------------------------
  293. //
  294. // Member: CTaskWizard::_DoWizard
  295. //
  296. // Synopsis: Create the wizard pages and invoke the wizard.
  297. //
  298. // Returns: HRESULT
  299. //
  300. // History: 5-20-1997 DavidMun Created
  301. //
  302. // Notes: If wizard is successfully created, doesn't return until
  303. // user hits Cancel or Finish.
  304. //
  305. //---------------------------------------------------------------------------
  306. HRESULT
  307. CTaskWizard::_DoWizard()
  308. {
  309. TRACE_METHOD(CTaskWizard, _DoWizard);
  310. HRESULT hr = S_OK;
  311. UINT i = 0;
  312. HPROPSHEETPAGE ahpsp[NUM_TASK_WIZARD_PAGES];
  313. ZeroMemory(ahpsp, sizeof(ahpsp));
  314. do
  315. {
  316. //
  317. // Create all the wizard pages
  318. //
  319. _apWizPages[TWP_WELCOME ] = new CWelcomePage (this, _tszFolderPath, &ahpsp[TWP_WELCOME ]);
  320. _apWizPages[TWP_SELECT_PROGRAM] = new CSelectProgramPage(this, _tszFolderPath, &ahpsp[TWP_SELECT_PROGRAM]);
  321. _apWizPages[TWP_SELECT_TRIGGER] = new CSelectTriggerPage(this, _tszFolderPath, &ahpsp[TWP_SELECT_TRIGGER]);
  322. _apWizPages[TWP_DAILY ] = new CDailyPage (this, _tszFolderPath, &ahpsp[TWP_DAILY ]);
  323. _apWizPages[TWP_WEEKLY ] = new CWeeklyPage (this, _tszFolderPath, &ahpsp[TWP_WEEKLY ]);
  324. _apWizPages[TWP_MONTHLY ] = new CMonthlyPage (this, _tszFolderPath, &ahpsp[TWP_MONTHLY ]);
  325. _apWizPages[TWP_ONCE ] = new COncePage (this, _tszFolderPath, &ahpsp[TWP_ONCE ]);
  326. #if !defined(_CHICAGO_)
  327. _apWizPages[TWP_PASSWORD ] = new CPasswordPage (this, _tszFolderPath, &ahpsp[TWP_PASSWORD ]);
  328. #endif // !defined(_CHICAGO_)
  329. _apWizPages[TWP_COMPLETION ] = new CCompletionPage (this, _tszFolderPath, &ahpsp[TWP_COMPLETION ]);
  330. //
  331. // Check that all objects and pages could be created
  332. //
  333. for (i = 0; i < NUM_TASK_WIZARD_PAGES; i++)
  334. {
  335. if (!_apWizPages[i] || !ahpsp[i])
  336. {
  337. hr = E_OUTOFMEMORY;
  338. break;
  339. }
  340. }
  341. //
  342. // Manually destroy the pages if one could not be created, then exit
  343. //
  344. if (FAILED(hr))
  345. {
  346. DEBUG_OUT((DEB_ERROR, "Creation failed, destroying pages\n"));
  347. for (i = 0; i < NUM_TASK_WIZARD_PAGES; i++)
  348. {
  349. if (ahpsp[i])
  350. {
  351. VERIFY(DestroyPropertySheetPage(ahpsp[i]));
  352. }
  353. else if (_apWizPages[i])
  354. {
  355. delete _apWizPages[i];
  356. }
  357. }
  358. break;
  359. }
  360. //
  361. // All pages created, display the wizard
  362. //
  363. PROPSHEETHEADER psh;
  364. ZeroMemory(&psh, sizeof(psh));
  365. #ifdef WIZARD97
  366. psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
  367. psh.pszbmWatermark = _fUse256ColorBmp ? MAKEINTRESOURCE(IDB_WATERMARK256) : MAKEINTRESOURCE(IDB_WATERMARK16);
  368. psh.pszbmHeader = _fUse256ColorBmp ? MAKEINTRESOURCE(IDB_BANNER256) : MAKEINTRESOURCE(IDB_BANNER16);
  369. #else
  370. psh.dwFlags = PSH_WIZARD;
  371. #endif // WIZARD97
  372. psh.dwSize = sizeof(psh);
  373. psh.hInstance = g_hInstance;
  374. psh.hwndParent = NULL;
  375. psh.pszCaption = NULL; // ignored for wizards; see CWelcome init
  376. psh.phpage = ahpsp;
  377. psh.nStartPage = 0;
  378. psh.nPages = NUM_TASK_WIZARD_PAGES;
  379. if (PropertySheet(&psh) == -1)
  380. {
  381. hr = HRESULT_FROM_WIN32(GetLastError());
  382. DEBUG_OUT_HRESULT(hr);
  383. }
  384. } while (0);
  385. return hr;
  386. }
  387. //+--------------------------------------------------------------------------
  388. //
  389. // Function: FindWizardEnumWndProc
  390. //
  391. // Synopsis: EnumWindows callback used to search for a create new task
  392. // wizard opened on the specified focus.
  393. //
  394. // Arguments: [hwnd] - top level window handle
  395. // [lParam] - pointer to SFindWiz struct
  396. //
  397. // Returns: TRUE - not found, continue enumeration
  398. // FALSE - found wizard, quit enumerating
  399. //
  400. // Modifies: SFindWiz struct pointed to by [lParam]
  401. //
  402. // History: 5-20-1997 DavidMun Created
  403. //
  404. //---------------------------------------------------------------------------
  405. BOOL CALLBACK
  406. FindWizardEnumWndProc(
  407. HWND hwnd,
  408. LPARAM lParam)
  409. {
  410. SFindWiz *pfw = (SFindWiz *) lParam;
  411. ULONG pid;
  412. GetWindowThreadProcessId(hwnd, &pid);
  413. do
  414. {
  415. //
  416. // If the window isn't in this process (explorer.exe) then ignore
  417. // it.
  418. //
  419. if (pid != GetCurrentProcessId())
  420. {
  421. break;
  422. }
  423. //
  424. // If it isn't the dialog class, it can't be a wizard.
  425. //
  426. if (!IsDialogClass(hwnd))
  427. {
  428. break;
  429. }
  430. //
  431. // Found a dialog window that was created by this process. If it's
  432. // a wizard, then it should return a valid window which is also of
  433. // dialog class.
  434. //
  435. HWND hwndPage = PropSheet_GetCurrentPageHwnd(hwnd);
  436. if (!IsWindow(hwndPage) || !IsDialogClass(hwndPage))
  437. {
  438. break;
  439. }
  440. //
  441. // Could be a wizard page. Ask it if it's THE wizard for the
  442. // focus. Note it's only possible to get away with sending a pointer
  443. // in the message because we've guaranteed the window belongs to this
  444. // process.
  445. //
  446. ULONG ulResult = (ULONG)SendMessage(hwndPage,
  447. g_msgFindWizard,
  448. 0,
  449. (LPARAM) pfw->tszFocus);
  450. if (ulResult == g_msgFindWizard)
  451. {
  452. pfw->fFound = TRUE;
  453. }
  454. } while (0);
  455. return !pfw->fFound; // continue enumerating if not found
  456. }
  457. //+--------------------------------------------------------------------------
  458. //
  459. // Member: CTaskWizard::_FindWizard
  460. //
  461. // Synopsis: Search through top level windows to find a create new task
  462. // wizard which is focused on [ptszFolderPath].
  463. //
  464. // Arguments: [ptszFolderPath] - wizard focus
  465. //
  466. // Returns: S_OK - found
  467. // S_FALSE - not found
  468. //
  469. // History: 5-20-1997 DavidMun Created
  470. //
  471. // Notes: BUGBUG change ptszFolderPath to server name
  472. //
  473. //---------------------------------------------------------------------------
  474. HRESULT
  475. CTaskWizard::_FindWizard(
  476. LPCTSTR ptszFolderPath)
  477. {
  478. SFindWiz fw = { FALSE, ptszFolderPath };
  479. if (!g_msgFindWizard)
  480. {
  481. g_msgFindWizard = RegisterWindowMessage(TEMPLATE_STR);
  482. }
  483. EnumWindows(FindWizardEnumWndProc, (LPARAM) &fw);
  484. return fw.fFound ? S_OK : S_FALSE;
  485. }
  486. #if (DBG == 1 && defined(_CHICAGO_))
  487. //+--------------------------------------------------------------------------
  488. //
  489. // Function: DebugMessageBox
  490. //
  491. // Synopsis: Display a message box for debugging output.
  492. //
  493. // History: 5-20-1997 DavidMun Created
  494. //
  495. //---------------------------------------------------------------------------
  496. VOID
  497. DebugMessageBox(ULONG flLevel, LPTSTR ptszFormat, ...)
  498. {
  499. va_list args;
  500. va_start(args, ptszFormat);
  501. if (flLevel & JobInfoLevel)
  502. {
  503. TCHAR tszBuf[SCH_XBIGBUF_LEN];
  504. wvsprintf(tszBuf, ptszFormat, args);
  505. MessageBox(NULL, tszBuf, TEXT("Debug"), MB_OK);
  506. }
  507. va_end(args);
  508. }
  509. #endif // (DBG == 1 && defined(_CHICAGO_))