//____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1996. // // File: jobidl.cxx // // Contents: // // Classes: // // Functions: // // Notes: For the first release of the scheduling agent, all security // operations are disabled under Win95, even Win95 to NT. // // History: 1/24/1996 RaviR Created // //____________________________________________________________________________ #include "..\pch\headers.hxx" #pragma hdrstop #include "dbg.h" #include "macros.h" #include "..\inc\resource.h" #include "resource.h" #include "..\wizard\resource.h" #include "..\inc\common.hxx" #include "jobidl.hxx" #include "sch_cls.hxx" // sched\inc #include "job_cls.hxx" // sched\inc #include "misc.hxx" // sched\inc #include "util.hxx" #include "..\schedui\schedui.hxx" #if !defined(_CHICAGO_) void SecurityErrorDialog( HWND hWndOwner, HRESULT hr); #endif // !defined(_CHICAGO_) ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////// //////// CJobID class implementation //////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //+-------------------------------------------------------------------------- // // Member: CJobID::InitToTemplate // // Synopsis: Inititialize this to represent a template object in the // folder. // // History: 05-15-1997 DavidMun Created // //--------------------------------------------------------------------------- void CJobID::InitToTemplate() { _id = ID_TEMPLATE; // // Name offset is at 1 so the first char can serve to make empty app // name, creator, and path strings. // _oCreator = 0; _oPath = 0; _oName = 1; LoadString(g_hInstance, IDS_TEMPLATE_NAME, &_cBuf[_oName], IDJOB_BUFFER_SIZE - 3); _cb = offsetof(CJobID, _cBuf) + (_oName + lstrlen(&_cBuf[_oName]) + 1) * sizeof(TCHAR); // ^^^ pidl size has to include offset into _cBuf _NullTerminate(); } //____________________________________________________________________________ // // Member: CJobID::Load // // Arguments: [pszFolderPath] -- IN // [pszJob] -- IN // // Returns: HRESULT. //____________________________________________________________________________ HRESULT CJobID::Load( LPCTSTR pszFolderPath, LPTSTR pszJob) // job path relative to Jobs folder with .job extension { DEBUG_OUT((DEB_USER12, "[CJobID::Load] <%ws, %ws>\n", pszFolderPath ? (LPWSTR)pszFolderPath : L"NULL FolderPath", pszJob)); #if DBG==1 TCHAR * pExt = PathFindExtension(pszJob); Win4Assert(lstrcmpi(pExt, TSZ_DOTJOB) == 0); #endif HRESULT hr = S_OK; CJob *pJob = NULL; ZeroMemory(this, sizeof(CJobID)); do { // // Set creation & last write times // TCHAR tcFile[MAX_PATH+1]; LPTSTR pFile = tcFile; if (pszFolderPath != NULL) { lstrcpy(tcFile, pszFolderPath); lstrcat(tcFile, TEXT("\\")); lstrcat(tcFile, pszJob); } else { pFile = pszJob; } // // Skip hidden jobs. // if (GetFileAttributes(pFile) & FILE_ATTRIBUTE_HIDDEN) { return S_FALSE; } HANDLE hFile = CreateFile(pFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile == INVALID_HANDLE_VALUE) { DEBUG_OUT_LASTERROR; hr = HRESULT_FROM_WIN32(GetLastError()); break; } if (GetFileTime(hFile, &_ftCreation, NULL, &_ftLastWrite) == FALSE) { CloseHandle(hFile); DEBUG_OUT_LASTERROR; hr = HRESULT_FROM_WIN32(GetLastError()); break; } CloseHandle(hFile); // // Create & load the job // hr = ::JFCreateAndLoadCJob(pszFolderPath, pszJob, &pJob); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); _id = ID_JOB; //////////////////////////////////////////////////////////// // // Extract the properties // // // Get last exit code // // The return value from this call is the task's last start error. // HRESULT hrLastStart = pJob->GetExitCode(&_dwExitCode); // // Get a code to tell what to display in the "Status" column. // For the purposes of this column the job can be: // a. missed // b. failed to start // c. running // d. other // ULONG ulAllFlags; pJob->GetAllFlags(&ulAllFlags); if (ulAllFlags & JOB_I_FLAG_MISSED) { _status = ejsMissed; } else if (FAILED(hrLastStart)) { switch(hrLastStart) { case HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE): _status = ejsBadAcct; break; case HRESULT_FROM_WIN32(ERROR_ACCOUNT_RESTRICTION): _status = ejsResAcct; break; default: _status = ejsWouldNotStart; } } else { HRESULT hrStatus = 0; hr = pJob->GetStatus(&hrStatus); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); switch (hrStatus) { case SCHED_S_TASK_RUNNING: _status = ejsRunning; break; case SCHED_S_TASK_NOT_SCHEDULED: _status = ejsNotScheduled; break; } } // // Get last run time // hr = pJob->GetMostRecentRunTime(&_stLastRunTime); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); // ensure wDayOfWeek is 0, else memcmp fails. _stLastRunTime.wDayOfWeek = 0; // // Get next run time // hr = pJob->GetNextRunTime(&_stNextRunTime); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); // ensure wDayOfWeek is 0, else memcmp fails. _stNextRunTime.wDayOfWeek = 0; // // Get the job flags // hr = pJob->GetFlags(&_ulJobFlags); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); // // Get the first job trigger if any // hr = pJob->GetTriggerCount(&_cTriggers); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); if (_cTriggers > 0) { ITaskTrigger * pIJobTrigger = NULL; hr = pJob->GetTrigger(0, &pIJobTrigger); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); _sJobTrigger.cbTriggerSize = sizeof(TASK_TRIGGER); hr = pIJobTrigger->GetTrigger(&_sJobTrigger); pIJobTrigger->Release(); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); } else { _sJobTrigger.cbTriggerSize = 0; } /////////////////////////////////////////////////////////////////// // // Fill up the buffer cBuf // USHORT cchCurr = 0; // // Get the command // LPWSTR pwszCommand = NULL; hr = pJob->GetApplicationName(&pwszCommand); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); #ifndef UNICODE hr = UnicodeToAnsi(_cBuf, pwszCommand, MAX_PATH); CoTaskMemFree(pwszCommand); BREAK_ON_FAIL(hr); #else lstrcpy(_cBuf, pwszCommand); CoTaskMemFree(pwszCommand); #endif DEBUG_OUT((DEB_USER12, "Command = %ws\n", _cBuf)); // update size cchCurr += lstrlen(_cBuf) + 1; // // Get the account name // _oCreator = cchCurr; LPWSTR pwszCreator = NULL; hr = pJob->GetCreator(&pwszCreator); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); #if defined(UNICODE) lstrcpy(&_cBuf[_oCreator], pwszCreator); CoTaskMemFree(pwszCreator); #else hr = UnicodeToAnsi(&_cBuf[_oCreator], pwszCreator, MAX_PATH); CoTaskMemFree(pwszCreator); BREAK_ON_FAIL(hr); #endif // update size cchCurr += lstrlen(&_cBuf[_oCreator]) + 1; // // Copy the job path // _oPath = cchCurr; if (pszFolderPath == NULL) { pszJob = PathFindFileName(pszJob); } lstrcpy(&_cBuf[_oPath], pszJob); TCHAR * ptcPath = &_cBuf[_oPath]; TCHAR * ptcName = PathFindFileName(ptcPath); TCHAR * ptcExtn = PathFindExtension(ptcName); if (ptcExtn) { *ptcExtn = TEXT('\0'); } _oName = _oPath + (USHORT)(ptcName - ptcPath) * sizeof(TCHAR); // update buff size cchCurr += lstrlen(ptcPath) + 1; // // Finaly set the size // _cb = offsetof(CJobID, _cBuf) + cchCurr * sizeof(TCHAR); // // Ensure that the DWORD at the end is zero, used by ILClone, etc. // _NullTerminate(); } while (0); if (pJob != NULL) { pJob->Release(); } return hr; } //____________________________________________________________________________ // // Member: CJobID::Rename // // Synopsis: Loads this object with data from jidIn, except for // the name which is set to lpszName. // // Arguments: [jidIn] -- IN // [lpszName] -- IN // // Returns: HRESULT. // // History: 1/25/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobID::Rename( CJobID & jidIn, LPCOLESTR lpszNameIn) { ZeroMemory(this, sizeof(CJobID)); CopyMemory(this, &jidIn, jidIn.GetSize()); LPTSTR lpszName = (LPTSTR)lpszNameIn; #if !defined(UNICODE) CHAR cBufTemp[MAX_PATH]; HRESULT hr = UnicodeToAnsi(cBufTemp, lpszNameIn, MAX_PATH); if (FAILED(hr)) { return hr; } lpszName = cBufTemp; #endif lstrcpy(&_cBuf[_oName], lpszName); _cb = offsetof(CJobID, _cBuf) + (_oName + lstrlen(lpszName) + 1) * sizeof(TCHAR); _NullTerminate(); return S_OK; } //____________________________________________________________________________ // // Member: CJobID::Clone // // Returns: CJobID * //____________________________________________________________________________ CJobID * CJobID::Clone(void) { CJobID * pjid = (CJobID *) SHAlloc(_cb + sizeof(_cb)); if (pjid) { CopyMemory(pjid, this, _cb); pjid->_NullTerminate(); } return pjid; } #if (DBG == 1) //+-------------------------------------------------------------------------- // // Member: CJobID::Validate // // Synopsis: Assert if this job idlist object is invalid // // History: 12-04-1997 DavidMun Created // // Notes: For debugging only. // //--------------------------------------------------------------------------- VOID CJobID::Validate() { // // Expect _cb to have been set to nonzero value // Win4Assert(_cb); Win4Assert(_cb < sizeof(CJobID)); // // Expect all jobids to have a name. Offset should be nonzero because // name is not the first string. // Win4Assert(_oName < IDJOB_BUFFER_SIZE); // // Expect that name is null terminated before the end of the buffer. // Win4Assert(_oName + lstrlen(GetName()) < IDJOB_BUFFER_SIZE); // // Expect the jobid itself to be null terminated // UNALIGNED USHORT *pusNextCB = (UNALIGNED USHORT *)(((BYTE *)this) + _cb); Win4Assert(_cb + sizeof(USHORT) <= sizeof(CJobID)); Win4Assert(!*pusNextCB); } #endif // (DBG == 1) BOOL GetLocaleDateTimeString( SYSTEMTIME* pst, DWORD dwDateFlags, DWORD dwTimeFlags, TCHAR szBuff[], int cchBuffLen, LPSHELLDETAILS lpDetails); //____________________________________________________________________________ // // Member: CJobID::GetNextRunTimeString // // Synopsis: S // // Arguments: [tcBuff] -- IN // [cchBuff] -- IN // [fForComparison] -- IN // // Returns: HRESULT. // // History: 4/25/1996 RaviR Created // //____________________________________________________________________________ LPTSTR CJobID::GetNextRunTimeString( TCHAR tcBuff[], UINT cchBuff, BOOL fForComparison, LPSHELLDETAILS lpDetails) { if (this->IsJobNotScheduled() == TRUE) { LoadString(g_hInstance, IDS_NEVER, tcBuff, cchBuff); } else if (this->IsJobFlagOn(TASK_FLAG_DISABLED) == TRUE) { LoadString(g_hInstance, IDS_DISABLED, tcBuff, cchBuff); } else if (this->IsTriggerFlagOn(TASK_TRIGGER_FLAG_DISABLED)) { LoadString(g_hInstance, IDS_TRIGGER_DISABLED, tcBuff, cchBuff); } else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_AT_SYSTEMSTART) { LoadString(g_hInstance, IDS_ON_STARTUP, tcBuff, cchBuff); } else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_AT_LOGON) { LoadString(g_hInstance, IDS_ON_LOGON, tcBuff, cchBuff); } else if (this->GetTriggerType() == TASK_EVENT_TRIGGER_ON_IDLE) { LoadString(g_hInstance, IDS_WHEN_IDLE, tcBuff, cchBuff); } else { SYSTEMTIME &st = this->GetNextRunTime(); if (st.wYear == 0 || st.wMonth == 0 || st.wDay == 0) { LoadString(g_hInstance, IDS_NEVER, tcBuff, cchBuff); } else { if (fForComparison == TRUE) { return NULL; } GetLocaleDateTimeString(&st, DATE_SHORTDATE, 0, tcBuff, cchBuff, lpDetails); } } return tcBuff; } //____________________________________________________________________________ // // Function: HDROPFromJobIDList // // Synopsis: Create an HDROP for the files in the apjid array. // Used for CF_HDROP format. // // Arguments: [cidl] -- IN // [apjidl] -- IN // // Returns: HDROP // // History: 1/31/1996 RaviR Created // //____________________________________________________________________________ HDROP HDROPFromJobIDList( LPCTSTR pszFolderPath, UINT cidl, PJOBID * apjidl) { HDROP hMem = 0; LPDROPFILESTRUCT lpDrop; DWORD dwSize = 0; if (cidl == 0) { return NULL; } TCHAR tcFolder[MAX_PATH]; lstrcpy(tcFolder, pszFolderPath); lstrcat(tcFolder, TEXT("\\")); USHORT cbFolderPathLen = (USHORT)(lstrlen(tcFolder) * sizeof(TCHAR)); // // Walk the list and find out how much space we need. // dwSize = sizeof(DROPFILESTRUCT) + sizeof(TCHAR); // size + terminal nul USHORT * pusPathLen = new USHORT[cidl * 2]; if (pusPathLen == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return NULL; } USHORT * pusExtLen = &pusPathLen[cidl]; for (UINT i=0; i < cidl; i++) { pusPathLen[i] = (USHORT)(lstrlen(apjidl[i]->GetPath()) * sizeof(TCHAR)); pusExtLen[i] = (USHORT)((lstrlen(apjidl[i]->GetExtension()) + 1) * sizeof(TCHAR)); dwSize += cbFolderPathLen + pusPathLen[i] + pusExtLen[i]; } // // If it's bigger than the struct can hold, then bail. // TODO: Return an error? // if (dwSize > 0x0000ffff) { delete [] pusPathLen; return NULL; } // // Allocate the buffer and fill it in. // hMem = (HDROP)GlobalAlloc(GHND, dwSize); if (hMem == NULL) { delete [] pusPathLen; CHECK_HRESULT(E_OUTOFMEMORY); return NULL; } lpDrop = (LPDROPFILESTRUCT) GlobalLock(hMem); lpDrop->pFiles = (DWORD)(sizeof(DROPFILESTRUCT)); lpDrop->pt.x = 0; lpDrop->pt.y = 0; lpDrop->fNC = FALSE; #ifdef UNICODE lpDrop->fWide = TRUE; #else lpDrop->fWide = FALSE; #endif // // Fill in the path names. // LPBYTE pbTemp = (LPBYTE) ((LPBYTE) lpDrop + lpDrop->pFiles); for (i=0; i < cidl; i++) { CopyMemory(pbTemp, tcFolder, cbFolderPathLen); pbTemp += cbFolderPathLen; CopyMemory(pbTemp, apjidl[i]->GetPath(), pusPathLen[i]); pbTemp += pusPathLen[i]; CopyMemory(pbTemp, apjidl[i]->GetExtension(), pusExtLen[i]); pbTemp += pusExtLen[i]; } *((LPTSTR)pbTemp) = TEXT('\0'); // Extra Nul terminate // // Unlock the buffer and return it. // GlobalUnlock(hMem); delete [] pusPathLen; return hMem; } //+-------------------------------------------------------------------------- // // Function: CreateIDListArray // // Synopsis: Create shell idlist array in the format required by the // CFSTR_SHELLIDLIST clipboard format. // // Arguments: [pidlFolder] - pidl of tasks folder // [cidl] - number of elements in [apjidl] // [apjidl] - array of pointers to idls, each idl // specifies a .job object. // // Returns: Handle to created array, or NULL on error. // // History: 05-30-1997 DavidMun Created // // Notes: For this format, the first element in the array is an // absolute idl to a container (the tasks folder), and the // remainder (each a single .job object) are relative to the // first. // //--------------------------------------------------------------------------- HGLOBAL CreateIDListArray( LPCITEMIDLIST pidlFolder, UINT cidl, PJOBID *apjidl) { TRACE_FUNCTION(CreateIDListArray); Win4Assert(cidl); if (cidl == 0) { return NULL; } HJOBIDA hJobIDA = NULL; DWORD offset = sizeof(CJobIDA) + sizeof(UINT) * cidl; DWORD dwSize = offset; for (UINT i=0; i < cidl ; i++) { dwSize += apjidl[i]->GetSize() + 2; // +2 for null list terminator } dwSize += ILGetSize(pidlFolder); hJobIDA = GlobalAlloc(GPTR, dwSize); // This MUST be GlobalAlloc!!! if (hJobIDA == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return NULL; } PJOBIDA pJobIDA = (PJOBIDA)hJobIDA; // no need to lock pJobIDA->cidl = cidl; // count doesn't include idl at offset 0, pJobIDA->aoffset[0] = offset; // which is container CopyMemory(((LPBYTE)pJobIDA)+offset, pidlFolder, ILGetSize(pidlFolder)); offset += ILGetSize(pidlFolder); for (i=0; i < cidl ; i++) { UINT cbSize = apjidl[i]->GetSize(); pJobIDA->aoffset[i+1] = offset; CopyMemory(((LPBYTE)pJobIDA)+offset, apjidl[i], cbSize); offset += cbSize + 2; // +2 to leave null after copied in idl } Win4Assert(offset == dwSize); return hJobIDA; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////// //////// CJobIDA related functions. //////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //____________________________________________________________________________ // // Function: HJOBIDA_Create // // Synopsis: Create an HJOBIDA for the files in the apjid array. // Used for CF_JOBIDLIST data format. // // Arguments: [cidl] -- IN // [apjidl] -- IN // // Returns: HJOBIDA // // History: 1/31/1996 RaviR Created // //____________________________________________________________________________ HJOBIDA HJOBIDA_Create( UINT cidl, PJOBID * apjidl) { if (cidl == 0) { return NULL; } HJOBIDA hJobIDA = NULL; DWORD offset = sizeof(CJobIDA) + sizeof(UINT) * (cidl - 1); DWORD dwSize = offset; for (UINT i=0; i < cidl ; i++) { dwSize += apjidl[i]->GetSize() + 2; // +2 for null list terminator } hJobIDA = GlobalAlloc(GPTR, dwSize); // This MUST be GlobalAlloc with // GPTR! if (hJobIDA == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return NULL; } PJOBIDA pJobIDA = (PJOBIDA)hJobIDA; // no need to lock pJobIDA->cidl = cidl; // // Note that apjidl[i] reports its true size, which doesn't include the // extra 0 ulong following it. That null terminator is required, and // isn't copied into pJobIDA by the CopyMemory, which is using // apjidl[i]'s reported size. // // Since the GPTR ensures zero-initialized memory, and the extra 2 // bytes per jobid has been accounted for in computing dwSize, we can // get the terminator just by increasing offset by the terminator size // on each iteration. // for (i=0; i < cidl ; i++) { UINT cbSize = apjidl[i]->GetSize(); pJobIDA->aoffset[i] = offset; CopyMemory(((LPBYTE)pJobIDA)+offset, apjidl[i], cbSize); offset += cbSize + 2; } Win4Assert(offset == dwSize); return hJobIDA; } void HJOBIDA_Free( HJOBIDA hJobIDA) { GlobalFree(hJobIDA); // This MUST be GlobalFree } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////// //////// Functions to clone and free a LPCITEMIDLIST array. //////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //____________________________________________________________________________ // // Function: ILA_Clone // // Synopsis: S // // Arguments: [cidl] -- IN // [apidl] -- IN // // Returns: LPITEMIDLIST // // History: 1/9/1996 RaviR Created // //____________________________________________________________________________ LPITEMIDLIST* ILA_Clone( UINT cidl, LPCITEMIDLIST * apidl) { TRACE_FUNCTION(ILA_Clone); LPITEMIDLIST* aNewPidl = new LPITEMIDLIST[cidl]; if (NULL == aNewPidl) { return NULL; } for (UINT i = 0; i < cidl; i++) { aNewPidl[i] = ILClone(apidl[i]); if (NULL == aNewPidl[i]) { // delete what we've allocated so far for (UINT j = 0; j < i; j++) { ILFree(aNewPidl[i]); } delete[] aNewPidl; return NULL; } } return aNewPidl; } //____________________________________________________________________________ // // Function: ILA_Free // // Synopsis: S // // Arguments: [cidl] -- IN // [apidl] -- IN // // Returns: VOID // // History: 1/9/1996 RaviR Created // //____________________________________________________________________________ VOID ILA_Free( UINT cidl, LPITEMIDLIST * apidl) { TRACE_FUNCTION(ILA_Free); for (UINT i = 0; i < cidl; i++) { ILFree(apidl[i]); } delete [] apidl; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////// //////// Functions to access the CJob & CSchedule //////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //____________________________________________________________________________ // // Function: JFGetJobScheduler // // Synopsis: S // // Arguments: [ppJobScheduler] -- IN // [ppwszFolderPath] -- IN // // Returns: HRESULT // // History: 1/25/1996 RaviR Created // //____________________________________________________________________________ HRESULT JFGetJobScheduler( LPTSTR pszMachine, ITaskScheduler ** ppJobScheduler, LPCTSTR *ppszFolderPath) { HRESULT hr = S_OK; CSchedule * pCSchedule = NULL; do { pCSchedule = new CSchedule; if (pCSchedule == NULL) { hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); break; } hr = pCSchedule->Init(); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); if (pszMachine != NULL) { #ifdef UNICODE hr = pCSchedule->SetTargetComputer(pszMachine); #else WCHAR wBuff[MAX_PATH]; hr = AnsiToUnicode(wBuff, pszMachine, MAX_PATH); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); hr = pCSchedule->SetTargetComputer(wBuff); #endif CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); } *ppszFolderPath = pCSchedule->GetFolderPath(); *ppJobScheduler = (ITaskScheduler *)pCSchedule; } while (0); if (FAILED(hr) && pCSchedule != NULL) { pCSchedule->Release(); } return hr; } //____________________________________________________________________________ // // Member: CreateAndLoadCJob // // Arguments: [pszJob] -- IN // [ppJob] -- OUT // // Returns: HRESULT. //____________________________________________________________________________ HRESULT JFCreateAndLoadCJob( LPCTSTR pszFolderPath, LPTSTR pszJob, // job path relative to the folder CJob ** ppJob) { TRACE_FUNCTION(CreateAndLoadCJob); *ppJob = NULL; // init for failure CJob *pJob = CJob::Create(); if (pJob == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return E_OUTOFMEMORY; } TCHAR buff[MAX_PATH]; LPTSTR pszJobPathTemp = pszJob; if (pszFolderPath != NULL) { lstrcpy(buff, pszFolderPath); lstrcat(buff, TEXT("\\")); lstrcat(buff, pszJob); pszJobPathTemp = buff; } HRESULT hr = S_OK; #if defined(UNICODE) LPWSTR pwszJobPath = pszJobPathTemp; #else WCHAR wcBuff[MAX_PATH]; hr = AnsiToUnicode(wcBuff, pszJobPathTemp, MAX_PATH); if (FAILED(hr)) { pJob->Release(); CHECK_HRESULT(hr); return hr; } LPWSTR pwszJobPath = wcBuff; #endif DEBUG_OUT((DEB_USER1, "Load Job <%ws>\n", pwszJobPath)); hr = pJob->Load(pwszJobPath, STGM_READWRITE | STGM_SHARE_EXCLUSIVE); if (FAILED(hr)) { pJob->Release(); CHECK_HRESULT(hr); return hr; } // // Success, return the object // *ppJob = pJob; return hr; } //+-------------------------------------------------------------------------- // // Function: JFCreateAndLoadTask // // Synopsis: Create an in-memory task object and initialize it from // [pszJob], returning the ITask interface on the object. // // Arguments: [pszFolderPath] - path to tasks folder // [pszJob] - filename of job // [ppITask] - filled with ITask interface ptr // // Returns: HRESULT // // Modifies: *[ppITask] // // History: 10-07-1997 DavidMun Created // // Notes: Caller must Release returned interface. // //--------------------------------------------------------------------------- HRESULT JFCreateAndLoadTask( LPCTSTR pszFolderPath, LPTSTR pszJob, // job path relative to the folder ITask ** ppITask) { TRACE_FUNCTION(CreateAndLoadTask); HRESULT hr; CJob *pJob; hr = JFCreateAndLoadCJob(pszFolderPath, pszJob, &pJob); if (SUCCEEDED(hr)) { hr = pJob->QueryInterface(IID_ITask, (void **)ppITask); pJob->Release(); } return hr; } //____________________________________________________________________________ // // Function: JFSaveJob // // Synopsis: Save task settings to storage via the task's IPersistFile // interface. Also, if applicable, prompt the user for security // account information. // // Arguments: [hwndOwner] -- Owner window. // [pIJob] -- Target task object. // [fSecuritySupported] -- Flag indicating if // security-specific code // should be invoked. // [fTaskAccountChange] -- TRUE, the task account // information has // changed. // [fTaskApplicationChange] -- TRUE, the task // application has // changed. // [fSuppressAccountInformationRequest] -- TRUE, do not prompt // the user for account // information. // // Returns: HRESULT // // History: 4/25/1996 RaviR Created // //____________________________________________________________________________ HRESULT JFSaveJob( HWND hwndOwner, ITask * pITask, BOOL fSecuritySupported, BOOL fTaskAccountChange, BOOL fTaskApplicationChange, BOOL fSuppressAccountInformationRequest) { #if defined(_CHICAGO_) Win4Assert(!fSecuritySupported); #endif // defined(_CHICAGO_) #if !defined(_CHICAGO_) AccountInfo AcctInfo; #endif // !defined(_CHICAGO_) HRESULT hr; IPersistFile * pipfTask; WCHAR * pwszAccountName = NULL; #if !defined(_CHICAGO_) BOOL fChangesSaved = FALSE; #endif // !defined(_CHICAGO_) hr = pITask->QueryInterface(IID_IPersistFile, (void **)&pipfTask); if (FAILED(hr)) { return hr; } #if !defined(_CHICAGO_) if (fSecuritySupported) { InitializeAccountInfo(&AcctInfo); // // Application change but no corresponding account information change. // Launch the set account information dialog in this case. // if (fTaskApplicationChange && !fTaskAccountChange) { // // Attempt to retreive account information for the set account // information dialog. Ignore failures, we would just like to // have something to fill in the account name control. // if (SUCCEEDED(pITask->GetAccountInformation(&pwszAccountName))) { AcctInfo.pwszAccountName = pwszAccountName; } goto SetAccountInformationDlg; } } #endif // !defined(_CHICAGO_) // // Go ahead and save the changes. // hr = pipfTask->Save(NULL, FALSE); #if !defined(_CHICAGO_) fChangesSaved = TRUE; #endif // !defined(_CHICAGO_) #if !defined(_CHICAGO_) if (fSecuritySupported) { if (FAILED(hr)) { if (pipfTask->IsDirty() == S_FALSE) { // // If Save failed, yet the job is no longer dirty, the // error is due to a failure setting security information. // // Let the user know there was a problem. Remap the return // code so we don't get further error dialogs. // CHECK_HRESULT(hr); SecurityErrorDialog(hwndOwner, hr); hr = S_OK; } #if DBG == 1 else { // // Standard persist code failure. Calling page code will // put up an error dialog. // CHECK_HRESULT(hr); } #endif // DBG == 1 goto CleanExit; } if (!fTaskAccountChange) { // // No account information changes. Verify that this job does // indeed have account information associated with it. // hr = pITask->GetAccountInformation(&pwszAccountName); if (hr == SCHED_E_ACCOUNT_INFORMATION_NOT_SET) { // // No account information. Launch the set account information // dialog. // hr = S_OK; goto SetAccountInformationDlg; } else if (SUCCEEDED(hr)) { // // Done. // goto CleanExit; } else { // // In error cases, silently fail. There's nothing we can do // about it other than confuse the user. Remapping the return // code so the calling page code doesn't put up an error // dialog. // CHECK_HRESULT(hr); hr = S_OK; goto CleanExit; } } else if (fTaskApplicationChange && fTaskAccountChange) { // // Fetch cached account information from the job object for // the pending set account information dialog. Silently fail // in an error case. // hr = pITask->GetAccountInformation(&pwszAccountName); Win4Assert(hr != SCHED_E_ACCOUNT_INFORMATION_NOT_SET); if (FAILED(hr) || hr == S_FALSE) { // // The information is cached. This would fail for no // reason other than insufficient memory. // // Though, did we goof? // CHECK_HRESULT(hr); hr = S_OK; goto CleanExit; } AcctInfo.pwszAccountName = pwszAccountName; } else { // // Done. // goto CleanExit; } } else { CHECK_HRESULT(hr); goto CleanExit; } SetAccountInformationDlg: // // Should've arrived here only for security reasons. // Win4Assert(fSecuritySupported); // // Can only arrive at this point if the user must specify security // account information. // // Launch the set account information dialog. // if (!fSuppressAccountInformationRequest) { LaunchSetAccountInformationDlg(hwndOwner, &AcctInfo); // // Check if the data is dirty. On dialog entry, the password is set // to the global empty string. If the password ptr still equals this, // then the user didn't change the password (e.g. the user canceled // the dialog). // if (AcctInfo.pwszAccountName != NULL && AcctInfo.pwszPassword != tszEmpty) { // // Reset the account information and persist the changes. // hr = pITask->SetAccountInformation(AcctInfo.pwszAccountName, AcctInfo.pwszPassword); fChangesSaved = FALSE; if (FAILED(hr)) { goto CleanExit; } } } if (!fChangesSaved) { CWaitCursor WaitCursor; hr = pipfTask->Save(NULL, FALSE); if (FAILED(hr) && pipfTask->IsDirty() == S_FALSE) { // // Similar check as above. General save succeeded but the attempt // to set security information failed. Let the user know there // was a problem and remap the return code so we don't get // further dialogs. // SecurityErrorDialog(hwndOwner, hr); hr = S_OK; } #if DBG == 1 else { CHECK_HRESULT(hr); } #endif // DBG == 1 } #endif // !defined(_CHICAGO_) #if !defined(_CHICAGO_) CleanExit: #endif // !defined(_CHICAGO_) pipfTask->Release(); #if !defined(_CHICAGO_) if (fSecuritySupported) { ResetAccountInfo(&AcctInfo); } #endif // !defined(_CHICAGO_) return hr; } #if !defined(_CHICAGO_) //____________________________________________________________________________ // // Function: SecurityErrorDialog // // Synopsis: Map the error to a hopefully friendly & informative dialog. // // Arguments: [hWndOwner] -- Parent window handle. // [hr] -- Security error to map. // // Returns: None. // // Notes: None. // //____________________________________________________________________________ void SecurityErrorDialog( HWND hWndOwner, HRESULT hr) { int idsErrorMessage; UINT idsHelpHint; idsErrorMessage = IERR_SECURITY_WRITE_ERROR; if (hr == SCHED_E_ACCOUNT_NAME_NOT_FOUND) { idsHelpHint = IDS_HELP_HINT_INVALID_ACCT; } else if (hr == SCHED_E_ACCOUNT_DBASE_CORRUPT) { idsHelpHint = IDS_HELP_HINT_DBASE_CORRUPT; } else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { idsHelpHint = IDS_HELP_HINT_ACCESS_DENIED; } else if (hr == SCHED_E_SERVICE_NOT_RUNNING || HRESULT_FACILITY(hr) == FACILITY_RPC) { idsHelpHint = IDS_HELP_HINT_SEC_GENERAL; } else { // // No help hint for unexpected errors. // idsHelpHint = 0; } // // Put up the error dialog. // SchedUIErrorDialog(hWndOwner, idsErrorMessage, hr, idsHelpHint); } #endif // !defined(_CHICAGO_) //____________________________________________________________________________ // // Function: JFGetAppNameForTask // // Synopsis: S // // Arguments: [path] -- IN // [pszAppName] -- IN // [cchAppName] -- IN // // Returns: HRESULT // // History: 4/25/1996 RaviR Created // //____________________________________________________________________________ HRESULT JFGetAppNameForTask( LPCTSTR pszTask, // Full path LPTSTR pszAppName, UINT cchAppName) { TRACE_FUNCTION(JFGetAppNameForTask); HRESULT hr = S_OK; CJob *pJob = CJob::Create(); if (pJob == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return E_OUTOFMEMORY; } hr = pJob->LoadP(pszTask, 0, FALSE, FALSE); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) { LPWSTR pwszCommand = NULL; hr = pJob->GetApplicationName(&pwszCommand); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) { #ifdef UNICODE lstrcpy(pszAppName, pwszCommand); DEBUG_OUT((DEB_USER1, "JFGetAppNameForTask -> %ws\n", pszAppName)); #else hr = UnicodeToAnsi(pszAppName, pwszCommand, cchAppName); #endif CoTaskMemFree(pwszCommand); } } pJob->Release(); return hr; } BOOL IsAScheduleObject( TCHAR szFile[]) { if( NULL == szFile ) { return FALSE; } LPTSTR pszName = PathFindFileName(szFile); LPTSTR pszExt = PathFindExtension(pszName); if (lstrcmpi(pszExt, TSZ_DOTJOB) != 0) // && (lstrcmpi(pszExt, g_szDotQue) != 0) { return FALSE; } return TRUE; } //____________________________________________________________________________ // // Function: JFCopyJob // // Synopsis: S // // Arguments: [hwndOwner] -- IN // [szFileFrom] -- IN // [pszFolderPath] -- IN // [fMove] -- IN // // Returns: HRESULT // // History: 2/2/1996 RaviR Created // //____________________________________________________________________________ HRESULT JFCopyJob( HWND hwndOwner, TCHAR szFileFrom[], LPCTSTR pszFolderPath, BOOL fMove) { HRESULT hr = S_OK; ITask * pJob = NULL; LPTSTR pszName = PathFindFileName(szFileFrom); hr = JFCreateAndLoadTask(NULL, szFileFrom, &pJob); if (FAILED(hr)) { if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) { SchedUIErrorDialog(hwndOwner, IERR_INVALID_DATA, pszName); } return hr; } else { pJob->Release(); } TCHAR szFileTo[MAX_PATH+1]; lstrcpy(szFileTo, pszFolderPath); SHFILEOPSTRUCT fo = {hwndOwner, (fMove ? FO_MOVE : FO_COPY), szFileFrom, szFileTo, FOF_ALLOWUNDO, FALSE, NULL, NULL}; // Make sure we have double trailing NULL! *(szFileFrom + lstrlen(szFileFrom) + 1) = TEXT('\0'); if ((SHFileOperation(&fo) !=0) || fo.fAnyOperationsAborted == TRUE) { hr = E_FAIL; CHECK_HRESULT(hr); return hr; } //SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATH, szFileFrom, szFileTo); return hr; } //____________________________________________________________________________ // // Function: GetTriggerStringFromTrigger // // Synopsis: S // // Arguments: [pJobTrigger] -- IN // [psTrigger] -- IN // [cchTrigger] -- IN // // Returns: HRESULT //____________________________________________________________________________ HRESULT GetTriggerStringFromTrigger( TASK_TRIGGER * pJobTrigger, LPTSTR psTrigger, UINT cchTrigger, LPSHELLDETAILS lpDetails) { HRESULT hr = S_OK; LPWSTR pwsz = NULL; if (pJobTrigger->cbTriggerSize > 0) { hr = ::StringFromTrigger(pJobTrigger, &pwsz, lpDetails); CHECK_HRESULT(hr); if (SUCCEEDED(hr)) { #if defined(UNICODE) lstrcpy(psTrigger, pwsz); #else hr = UnicodeToAnsi(psTrigger, pwsz, cchTrigger); #endif CoTaskMemFree(pwsz); } } else { LoadString(g_hInstance, IDS_JOB_NOT_SCHEDULED, psTrigger, cchTrigger); } return hr; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////// //////// Misc functions. //////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// LPITEMIDLIST * SHIDLFromJobIDL( UINT cidl, PJOBID * apjidl) { LPITEMIDLIST * apidlOut = (LPITEMIDLIST *)SHAlloc( sizeof(LPITEMIDLIST) * cidl); if (apidlOut) { for (UINT i=0; i < cidl; i++) { apidlOut[i] = ILCreateFromPath(apjidl[i]->GetPath()); if (apidlOut[i] == NULL) { break; } } if (i < cidl) // => memory error { while (i--) { ILFree(apidlOut[i]); } SHFree(apidlOut); apidlOut = NULL; } } #if DBG==1 if (apidlOut == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); } #endif return apidlOut; }