//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1996. // // File: taskwiz.cxx // // Contents: Class which creates and invokes the 'create new task' wizard. // // Classes: CTaskWizard // // History: 5-20-1997 DavidMun Created // //--------------------------------------------------------------------------- #include "..\pch\headers.hxx" #pragma hdrstop #include "myheaders.hxx" #include "..\folderui\jobidl.hxx" // // Types // // SFindWiz - passed to window enumeration function. BUGBUG when wizard // on remote machine is supported, the 'tszFocus' member should be the // server name. For now, it is just the path to the tasks folder. // struct SFindWiz { BOOL fFound; LPCTSTR tszFocus; }; // // Globals // // g_msgFindWizard - private window message used to interrogate the wizard // dialog proc during the find operation. // // TEMPLATE_STR - string used to create private message, also used by // folderui code to identify the template icon. // UINT g_msgFindWizard; extern const TCHAR TEMPLATE_STR[]; // // External references // extern HRESULT QuietStartContinueService(); // ..\folderui\schstate.cxx extern HRESULT JFGetDataObject( LPCTSTR pszFolderPath, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST * apidl, BOOL fCut, LPVOID * ppvObj); extern HRESULT DisplayJobProperties( LPDATAOBJECT pdtobj); //+-------------------------------------------------------------------------- // // Member: CTaskWizard::CTaskWizard // // Synopsis: ctor // // Arguments: [ptszFolderPath] - path to tasks folder // // History: 5-12-1997 DavidMun Created // //--------------------------------------------------------------------------- CTaskWizard::CTaskWizard( LPCTSTR ptszFolderPath, LPITEMIDLIST pidlFolder) { TRACE_CONSTRUCTOR(CTaskWizard); SecureZeroMemory(_apWizPages, sizeof _apWizPages); _fAdvanced = FALSE; _tszJobObjectFullPath[0] = TEXT('\0'); _pTask = NULL; lstrcpyn(_tszFolderPath, ptszFolderPath, ARRAYLEN(_tszFolderPath)); _pidlFolder = pidlFolder; #ifdef WIZARD97 _fUse256ColorBmp = Is256ColorSupported(); #endif // WIZARD97 } //+-------------------------------------------------------------------------- // // Member: CTaskWizard::~CTaskWizard // // Synopsis: dtor // // History: 5-19-1997 DavidMun Created // //--------------------------------------------------------------------------- CTaskWizard::~CTaskWizard() { TRACE_DESTRUCTOR(CTaskWizard); if (_pTask) { _pTask->Release(); } ILFree(_pidlFolder); } //+-------------------------------------------------------------------------- // // Member: CTaskWizard::Launch, static // // Synopsis: Run the task wizard in a separate thread. // // Arguments: [ptszFolderPath] - path to tasks folder. // // Returns: HRESULT // // History: 5-19-1997 DavidMun Created // // Notes: If an instance of the wizard is already running for the // target machine, makes that the foreground window and // returns. // //--------------------------------------------------------------------------- HRESULT CTaskWizard::Launch( LPCTSTR ptszFolderPath, LPCITEMIDLIST pidlFolder) { TRACE_FUNCTION(CTaskWizard::Launch); HRESULT hr = S_OK; CTaskWizard *pNewWiz = NULL; do { // // Start the service if it isn't running, or continue it if it is // paused. Since this is the wizard, do it on behalf of the user // without asking first. // // Continue on failure, since it is better to let the user at least // create the task, even if the service can't be started (user might // not have permission). // hr = QuietStartContinueService(); CHECK_HRESULT(hr); // // Create a path string that CPropPage will store. This is the // full path to the tasks folder, with a trailing backslash. The // CPropPage will truncate at the last backslash, since most other // callers give it a task filename. // ULONG cchPath = lstrlen(ptszFolderPath); if (cchPath >= MAX_PATH - 1) // reserve space for trailing backslash { hr = E_INVALIDARG; DEBUG_OUT_HRESULT(hr); break; } TCHAR tszFolderPath[MAX_PATH + 1]; StringCchCopy(tszFolderPath, MAX_PATH + 1, ptszFolderPath); tszFolderPath[cchPath] = TEXT('\\'); tszFolderPath[cchPath + 1] = TEXT('\0'); // // Look for an instance of the wizard running and focused on our // folder path. If one is found, it will make itself foreground // window, and we can quit. // hr = _FindWizard(tszFolderPath); if (hr == S_OK) { break; } // // No wizard is up for the current focus. Create a wizard object // and run it in a new thread. // LPITEMIDLIST pidlFolderCopy = ILClone(pidlFolder); if (!pidlFolderCopy) { hr = E_OUTOFMEMORY; DEBUG_OUT_HRESULT(hr); break; } pNewWiz = new CTaskWizard(tszFolderPath, pidlFolderCopy); if (!pNewWiz) { ILFree(pidlFolderCopy); hr = E_OUTOFMEMORY; DEBUG_OUT_HRESULT(hr); break; } HANDLE hThread; DWORD idThread; hThread = CreateThread(NULL, 0, _WizardThreadProc, (LPVOID) pNewWiz, 0, &idThread); if (!hThread) { delete pNewWiz; DEBUG_OUT_LASTERROR; hr = HRESULT_FROM_LASTERROR; break; } VERIFY(CloseHandle(hThread)); } while (0); return hr; } //+-------------------------------------------------------------------------- // // Member: CTaskWizard::_WizardThreadProc, static // // Synopsis: Displays the wizard (and optionally task property sheet) // using a separate thread. // // Arguments: [pvThis] - CTaskWizard pointer // // Returns: HRESULT // // History: 5-20-1997 DavidMun Created // // Notes: The wizard runs in a separate thread so the explorer ui // isn't stalled. // //--------------------------------------------------------------------------- DWORD WINAPI CTaskWizard::_WizardThreadProc( LPVOID pvThis) { HRESULT hr = OleInitialize(NULL); if (FAILED(hr)) { DEBUG_OUT_HRESULT(hr); return hr; } CTaskWizard *pThis = (CTaskWizard *)pvThis; __try { hr = pThis->_DoWizard(); // // Once _DoWizard returns, the wizard property sheet has closed. // // If the user elected to see the new task's property sheet, then // _fAdvanced will be set, and the completion page should have // set a valid filename and interface pointer for the task. // // Open the property sheet while we're still in the thread. // if (SUCCEEDED(hr) && pThis->_fAdvanced) { DEBUG_ASSERT(pThis->_pTask); DEBUG_ASSERT(*pThis->_tszJobObjectFullPath); // // Since we want to see the security page if the object is on NT // on an NTFS partition, we'll have to call the version of // DisplayJobProperties that takes a data object. // // To get a data object describing the task object, we need an // itemid for the job, so create one. // CJobID jid; jid.LoadDummy(pThis->_tszJobObjectFullPath); LPCITEMIDLIST pidl = (LPCITEMIDLIST) &jid; LPDATAOBJECT pdo = NULL; TCHAR tszFolderPath[MAX_PATH + 1]; StringCchCopy(tszFolderPath, MAX_PATH + 1, pThis->_tszFolderPath); LPTSTR ptszLastSlash = _tcsrchr(tszFolderPath, TEXT('\\')); if (ptszLastSlash && lstrlen(ptszLastSlash) == 1) { *ptszLastSlash = TEXT('\0'); } hr = JFGetDataObject(tszFolderPath, // path to tasks dir pThis->_pidlFolder, // itemid of tasks folder 1, // one itemid in array &pidl, // namely, this one FALSE, // not doing cut/paste (VOID **) &pdo); if (SUCCEEDED(hr)) { hr = DisplayJobProperties(pdo); CHECK_HRESULT(hr); } else { DEBUG_OUT_HRESULT(hr); } } delete pThis; } __finally { OleUninitialize(); } return (DWORD) hr; } //+-------------------------------------------------------------------------- // // Member: CTaskWizard::_DoWizard // // Synopsis: Create the wizard pages and invoke the wizard. // // Returns: HRESULT // // History: 5-20-1997 DavidMun Created // // Notes: If wizard is successfully created, doesn't return until // user hits Cancel or Finish. // //--------------------------------------------------------------------------- HRESULT CTaskWizard::_DoWizard() { TRACE_METHOD(CTaskWizard, _DoWizard); HRESULT hr = S_OK; UINT i = 0; HPROPSHEETPAGE ahpsp[NUM_TASK_WIZARD_PAGES]; SecureZeroMemory(ahpsp, sizeof(ahpsp)); do { // // Create all the wizard pages // _apWizPages[TWP_WELCOME ] = new CWelcomePage (this, _tszFolderPath, &ahpsp[TWP_WELCOME ]); _apWizPages[TWP_SELECT_PROGRAM] = new CSelectProgramPage(this, _tszFolderPath, &ahpsp[TWP_SELECT_PROGRAM]); _apWizPages[TWP_SELECT_TRIGGER] = new CSelectTriggerPage(this, _tszFolderPath, &ahpsp[TWP_SELECT_TRIGGER]); _apWizPages[TWP_DAILY ] = new CDailyPage (this, _tszFolderPath, &ahpsp[TWP_DAILY ]); _apWizPages[TWP_WEEKLY ] = new CWeeklyPage (this, _tszFolderPath, &ahpsp[TWP_WEEKLY ]); _apWizPages[TWP_MONTHLY ] = new CMonthlyPage (this, _tszFolderPath, &ahpsp[TWP_MONTHLY ]); _apWizPages[TWP_ONCE ] = new COncePage (this, _tszFolderPath, &ahpsp[TWP_ONCE ]); _apWizPages[TWP_PASSWORD ] = new CPasswordPage (this, _tszFolderPath, &ahpsp[TWP_PASSWORD ]); _apWizPages[TWP_COMPLETION ] = new CCompletionPage (this, _tszFolderPath, &ahpsp[TWP_COMPLETION ]); // // Check that all objects and pages could be created // for (i = 0; i < NUM_TASK_WIZARD_PAGES; i++) { if (!_apWizPages[i] || !ahpsp[i]) { hr = E_OUTOFMEMORY; break; } } // // Manually destroy the pages if one could not be created, then exit // if (FAILED(hr)) { DEBUG_OUT((DEB_ERROR, "Creation failed, destroying pages\n")); for (i = 0; i < NUM_TASK_WIZARD_PAGES; i++) { if (ahpsp[i]) { VERIFY(DestroyPropertySheetPage(ahpsp[i])); } else if (_apWizPages[i]) { delete _apWizPages[i]; } } break; } // // All pages created, display the wizard // PROPSHEETHEADER psh; SecureZeroMemory(&psh, sizeof(psh)); #ifdef WIZARD97 psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER; psh.pszbmWatermark = _fUse256ColorBmp ? MAKEINTRESOURCE(IDB_WATERMARK256) : MAKEINTRESOURCE(IDB_WATERMARK16); psh.pszbmHeader = _fUse256ColorBmp ? MAKEINTRESOURCE(IDB_BANNER256) : MAKEINTRESOURCE(IDB_BANNER16); #else psh.dwFlags = PSH_WIZARD; #endif // WIZARD97 psh.dwSize = sizeof(psh); psh.hInstance = g_hInstance; psh.hwndParent = NULL; psh.pszCaption = NULL; // ignored for wizards; see CWelcome init psh.phpage = ahpsp; psh.nStartPage = 0; psh.nPages = NUM_TASK_WIZARD_PAGES; if (PropertySheet(&psh) == -1) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUG_OUT_HRESULT(hr); } } while (0); return hr; } //+-------------------------------------------------------------------------- // // Function: FindWizardEnumWndProc // // Synopsis: EnumWindows callback used to search for a create new task // wizard opened on the specified focus. // // Arguments: [hwnd] - top level window handle // [lParam] - pointer to SFindWiz struct // // Returns: TRUE - not found, continue enumeration // FALSE - found wizard, quit enumerating // // Modifies: SFindWiz struct pointed to by [lParam] // // History: 5-20-1997 DavidMun Created // //--------------------------------------------------------------------------- BOOL CALLBACK FindWizardEnumWndProc( HWND hwnd, LPARAM lParam) { SFindWiz *pfw = (SFindWiz *) lParam; ULONG pid; GetWindowThreadProcessId(hwnd, &pid); do { // // If the window isn't in this process (explorer.exe) then ignore // it. // if (pid != GetCurrentProcessId()) { break; } // // If it isn't the dialog class, it can't be a wizard. // if (!IsDialogClass(hwnd)) { break; } // // Found a dialog window that was created by this process. If it's // a wizard, then it should return a valid window which is also of // dialog class. // HWND hwndPage = PropSheet_GetCurrentPageHwnd(hwnd); if (!IsWindow(hwndPage) || !IsDialogClass(hwndPage)) { break; } // // Could be a wizard page. Ask it if it's THE wizard for the // focus. Note it's only possible to get away with sending a pointer // in the message because we've guaranteed the window belongs to this // process. // ULONG ulResult = (ULONG)SendMessage(hwndPage, g_msgFindWizard, 0, (LPARAM) pfw->tszFocus); if (ulResult == g_msgFindWizard) { pfw->fFound = TRUE; } } while (0); return !pfw->fFound; // continue enumerating if not found } //+-------------------------------------------------------------------------- // // Member: CTaskWizard::_FindWizard // // Synopsis: Search through top level windows to find a create new task // wizard which is focused on [ptszFolderPath]. // // Arguments: [ptszFolderPath] - wizard focus // // Returns: S_OK - found // S_FALSE - not found // // History: 5-20-1997 DavidMun Created // // Notes: BUGBUG change ptszFolderPath to server name // //--------------------------------------------------------------------------- HRESULT CTaskWizard::_FindWizard( LPCTSTR ptszFolderPath) { SFindWiz fw = { FALSE, ptszFolderPath }; if (!g_msgFindWizard) { g_msgFindWizard = RegisterWindowMessage(TEMPLATE_STR); } EnumWindows(FindWizardEnumWndProc, (LPARAM) &fw); return fw.fFound ? S_OK : S_FALSE; }