////////////////////////////////////////////////////////////////////////////// // // SCHEDWIZ.CPP / Tuneup // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1998 // All rights reserved // // Functions for the summary wizard page. // // 8/98 - Jason Cohen (JCOHEN) // ////////////////////////////////////////////////////////////////////////////// // // Internal include file(s). // #include #include #include "schedwiz.h" #include "main.h" //#include "resource.h" //#include "mstask.h" #include //#include // // Internal defined value(s). // #define TASK_BIMONTH_ODD (TASK_JANUARY | TASK_MARCH | TASK_MAY | TASK_JULY | TASK_SEPTEMBER | TASK_NOVEMBER) #define TASK_BIMONTH_EVEN (TASK_FEBRUARY | TASK_APRIL | TASK_JUNE | TASK_AUGUST | TASK_OCTOBER | TASK_DECEMBER) #define TASK_QUARTER_1 (TASK_JANUARY | TASK_MAY | TASK_SEPTEMBER) #define TASK_QUARTER_2 (TASK_FEBRUARY | TASK_JUNE | TASK_OCTOBER) #define TASK_QUARTER_3 (TASK_MARCH | TASK_JULY | TASK_NOVEMBER) #define TASK_QUARTER_4 (TASK_APRIL | TASK_AUGUST | TASK_DECEMBER) #define TASK_WHOLE_YEAR (TASK_BIMONTH_ODD | TASK_BIMONTH_EVEN) // // Internal defined macro(s). // #define E_JOB_FAIL(x) (x == E_OUTOFMEMORY ? IDS_OUTOFMEMORY : IDS_JOB_CREATE_FAIL) // // Internal global variable(s). // ITaskScheduler *g_psa = NULL; // // Inernal function prototype(s). // static VOID InitJobTime(TASK_TRIGGER *, INT, INT); static BOOL GetJobFileName(LPTSTR, LPTSTR); static VOID IncDate(LPWORD, LPWORD, LPWORD, INT); static BOOL DeleteOrgJobFile(LPTSTR); static INT WeekDayToNum(INT); static VOID taskSetNextDay(TASK_TRIGGER *); static BOOL IsScheduledTasks(LPTASKDATA); static BOOL GetTaskTrigger(ITask *, TASK_TRIGGER *); // // External function(s). // BOOL InitJobs(LPTASKDATA lpGlobalTasks) { ITaskTrigger *pTrigger = NULL; WORD wTrigger; HRESULT hResult; BOOL bErr = FALSE; LPTASKDATA lpTask; #ifdef _UNICODE LPWSTR lpwBuffer; #else // _UNICODE WCHAR szwBuffer[256]; LPWSTR lpwBuffer = szwBuffer; #endif // _UNICODE // Initialize the COM library. // if ( ( (hResult = CoInitialize(NULL)) != S_OK ) && (hResult == S_FALSE) ) return FALSE; // Initialize ISchedulingAgent. // if ( CoCreateInstance(CLSID_CSchedulingAgent, NULL, CLSCTX_INPROC_SERVER, IID_ISchedulingAgent, (void **) &g_psa) != S_OK ) return FALSE; for (lpTask = lpGlobalTasks; lpTask && !bErr; lpTask = lpTask->lpNext) { // Load the task (.job) with ITaskScheduler::Activate(). // ANSIWCHAR(lpwBuffer, lpTask->lpJobName, sizeof(szwBuffer)); if ( (hResult = g_psa->Activate((LPCWSTR) lpwBuffer, IID_ITask, (IUnknown**) &lpTask->pTask)) == E_OUTOFMEMORY ) bErr = ErrMsg(NULL, IDS_OUTOFMEMORY); else { // We should search for a task with the same app name if the // above activate call failed. // if ( hResult == S_OK ) { // Get the existing flags for the job with IScheduledWorkItem::GetFlags(). // if ( (hResult = lpTask->pTask->GetFlags(&lpTask->dwFlags)) == S_OK ) { // Setup our internal flags for the task. // if ( lpTask->dwFlags & TASK_FLAG_DISABLED ) lpTask->dwOptions &= ~TASK_SCHEDULED; else lpTask->dwOptions |= TASK_SCHEDULED; // IScheduledWorkItem::GetTrigger(). // // TODO: why do we need this data saved. // if ( (hResult = lpTask->pTask->GetTrigger((WORD) 0, &pTrigger)) == S_OK ) { pTrigger->GetTrigger(&lpTask->Trigger); pTrigger->Release(); } } } // If we didn't load the entire task successfully, we should // delete any that is there and create a new one. // if (hResult != S_OK) { // Delete existing (maybe corrupted) job file. // if ( !DeleteOrgJobFile(lpTask->lpJobName) ) bErr = ErrMsg(NULL, IDS_DEL_FILE); else { ANSIWCHAR(lpwBuffer, lpTask->lpJobName, sizeof(szwBuffer)); hResult = g_psa->NewWorkItem((LPCWSTR) lpwBuffer, CLSID_CTask, IID_ITask, (IUnknown**) &lpTask->pTask); if ( (hResult != S_OK) || (lpTask->pTask == NULL) ) bErr = ErrMsg(NULL, E_JOB_FAIL(hResult)); else { // Make sure Tuneup knows this is a new task and is // scheduled by default. // lpTask->dwOptions |= TASK_NEW; lpTask->dwOptions |= TASK_SCHEDULED; // Set the application name to the full path name of the task. // ANSIWCHAR(lpwBuffer, lpTask->lpFullPathName, sizeof(szwBuffer)); lpTask->pTask->SetApplicationName((LPCWSTR) lpwBuffer); // Set the working directory for the task (always empty string). // lpTask->pTask->SetWorkingDirectory((LPCWSTR) L""); // Set the parameters for the task (not required). // if ( lpTask->lpParameters ) { ANSIWCHAR(lpwBuffer, lpTask->lpParameters, sizeof(szwBuffer)); lpTask->pTask->SetParameters(lpwBuffer); } // Set the comment for the task (not required). // if ( lpTask->lpComment ) { ANSIWCHAR(lpwBuffer, lpTask->lpComment, sizeof(szwBuffer)); lpTask->pTask->SetComment(lpwBuffer); } // Set the default flags for the task. // lpTask->pTask->SetFlags(lpTask->dwFlags); // For some reason we do this for all tasks // but cleanup. // if ( !( lpTask->dwOptions & TASK_NOIDLE ) ) lpTask->pTask->SetIdleWait(10, 999); // Create trigger item. // if ( (hResult = lpTask->pTask->CreateTrigger(&wTrigger, &pTrigger)) != S_OK) bErr = ErrMsg(NULL, E_JOB_FAIL(hResult)); else { InitJobTime(&lpTask->Trigger, lpTask->nSchedule, g_nTimeScheme); pTrigger->SetTrigger(&lpTask->Trigger); pTrigger->Release(); } } } } } } if (bErr) ReleaseJobs(lpGlobalTasks, FALSE); return bErr; } VOID ReleaseJobs(LPTASKDATA lpGlobalTasks, BOOL bFinish) { ITaskTrigger *pTrigger; IPersistFile *pPersistFile; LPTASKDATA lpTask; for (lpTask = lpGlobalTasks; lpTask; lpTask = lpTask->lpNext) { // Check to see if used in initialization fail handler // or the item is not needed. // if ( lpTask->pTask != (ITask*) NULL ) { if ( ( lpTask->dwOptions & TASK_NEW ) && !bFinish ) { // The .job is newly created, and user choose Cancel. // DeleteOrgJobFile(lpTask->lpJobName); } else { // Even if the item is not scheduled, we still save it, because we // use the Enable/Disable flag in the .job to keep the Yes/No state. // if (bFinish) { // Take care the flag only, since the Task_Trigger is // auto saved in Schedule property page. // if ( !(g_dwFlags & TUNEUP_CUSTOM) || (lpTask->dwOptions & TASK_SCHEDULED) ) lpTask->dwFlags &= ~TASK_FLAG_DISABLED; else lpTask->dwFlags |= TASK_FLAG_DISABLED; } else { // User canceled so restore Task_Trigger. // if ( lpTask->pTask->GetTrigger((WORD) 0, &pTrigger) == S_OK ) { pTrigger->SetTrigger(&lpTask->Trigger); pTrigger->Release(); } } // Set or restore flags. // lpTask->pTask->SetFlags(lpTask->dwFlags); // Save the file, release the interfaces. // if ( lpTask->pTask->QueryInterface(IID_IPersistFile, (VOID **) &pPersistFile) == S_OK ) { pPersistFile->Save((LPCOLESTR) NULL, TRUE); pPersistFile->Release(); } lpTask->pTask->Release(); /* BUGBUG: I don't understand why this is here! // Rename the old task. // if ( ItemData[i].lpOldTaskName ) { if ( bSave ) { TCHAR szSrc[MAX_PATH], szTgt[MAX_PATH], *ptr; //GetJobFileName(i, szTgt); // get filename for delete or hide DeleteFile(szTgt); lstrcpy(szSrc, szTgt); if ( ptr = strrchr(szSrc, '\\') ) lstrcpy(ptr+1, ItemData[i].lpOldTaskName); MoveFile(szSrc, szTgt); } } */ } } } // Release ISchedulingAgent. // g_psa->Release(); // Close the OLE COM library. // CoUninitialize(); } ////////////////////////////////////////////////////////////////////////////// // // EXTERNAL: // JobReschedule() // - Reschedules a particular job. // // ENTRY: // hDlg - Parent dialog for property sheet. // // EXIT: // BOOL // ////////////////////////////////////////////////////////////////////////////// BOOL JobReschedule(HWND hDlg, ITask * pJob) { HPROPSHEETPAGE hpsp[1]; PROPSHEETHEADER psh; TASK_TRIGGER OldTrigger, NewTrigger; IProvideTaskPage *pProvideTaskPage; LPTSTR lpCaption; if ( pJob->QueryInterface(IID_IProvideTaskPage, (VOID**) &pProvideTaskPage) != S_OK ) return FALSE; // We need the Schedule page only. // if ( pProvideTaskPage->GetPage(TASKPAGE_SCHEDULE, TRUE, &(hpsp[0])) != S_OK ) return FALSE; // Get the caption string. // lpCaption = AllocateString(NULL, IDS_RESCHED); // Setup the property page header. // psh.dwSize = sizeof(PROPSHEETHEADER); psh.dwFlags = PSH_DEFAULT | PSH_NOAPPLYNOW; psh.hwndParent = hDlg; psh.nPages = 1; psh.nStartPage = 0; psh.phpage = (HPROPSHEETPAGE *) hpsp; psh.pszCaption = lpCaption; // Keep original trigger. // GetTaskTrigger(pJob, &OldTrigger); // Display the property sheet page. // PropertySheet(&psh); // Release the page and other resources. // FREE(lpCaption); pProvideTaskPage->Release(); // Get the new trigger, compare it to see whether it's changed. // GetTaskTrigger(pJob, &NewTrigger); // If the new time and the old time don't compare, then // we must change the time scheme to custom. // if ( memcmp((const void *) &OldTrigger, (const void *) &NewTrigger, sizeof(TASK_TRIGGER)) == 0 ) return FALSE; return TRUE; } LPTSTR GetTaskTriggerText(ITask * pTask) { LPWSTR lpwBuffer; LPTSTR lpReturn = NULL; #ifdef _UNICODE LPTSTR lpBuffer; #else // _UNICODE TCHAR szBuffer[256]; LPTSTR lpBuffer = szBuffer; #endif // _UNICODE if ( pTask->GetTriggerString((WORD) 0, (LPWSTR *) &lpwBuffer) == S_OK ) { // Convert the string if _UNICODE is not defined and set the // window to the new text. // WCHARANSI(lpBuffer, lpwBuffer, sizeof(szBuffer)); if ( lpReturn = (LPTSTR) MALLOC(sizeof(TCHAR) * (lstrlen(lpBuffer) + 1)) ) lstrcpy(lpReturn, lpBuffer); // Free the string returned from IScheduledWorkitem::GetTriggerString(). // CoTaskMemFree(lpwBuffer); } return lpReturn; } LPTSTR GetNextRunTimeText(ITask * pTask, DWORD dwFlags) { TCHAR szTime[128], szDate[128]; LPTSTR lpReturn = NULL; SYSTEMTIME stm; // If it's disabled, we can't get run time string. // JobRelease will clear it if the user cancels. // if ( dwFlags & TASK_FLAG_DISABLED ) { dwFlags &= ~TASK_FLAG_DISABLED; pTask->SetFlags(dwFlags); } pTask->GetNextRunTime(&stm); if ( ( GetTimeFormat(GetUserDefaultLCID(), TIME_NOSECONDS, &stm, NULL, (LPTSTR) szTime, sizeof(szTime) / sizeof(TCHAR)) ) && ( GetDateFormat(GetUserDefaultLCID(), DATE_LONGDATE, &stm, NULL, (LPTSTR) szDate, sizeof(szDate) / sizeof(TCHAR)) ) && ( lpReturn = (LPTSTR) MALLOC(sizeof(TCHAR) * (lstrlen(szTime) + lstrlen(szDate) + 3)) ) ) { wsprintf(lpReturn, _T("%s, %s"), szTime, szDate); } return lpReturn; } VOID SetTimeScheme(INT nTimeScheme) { ITaskTrigger *pTrigger; TASK_TRIGGER SchemeTrigger; LPTASKDATA lpTask; // Reset the static values in InitJobTime() since // we are resetting all the job times. // InitJobTime(NULL, 0, 0); // Go through all the tasks and update the task trigger for // the new time scheme. // for (lpTask = g_Tasks; lpTask; lpTask = lpTask->lpNext) { // Get the ITaskTrigger interface so we can set the task trigger. // if (lpTask->pTask->GetTrigger((WORD) 0, &pTrigger) == S_OK) { // Get the new task trigger for this job. // InitJobTime(&SchemeTrigger, lpTask->nSchedule, nTimeScheme); // Save the new task trigger to the job. // pTrigger->SetTrigger(&SchemeTrigger); // Release the ITaskTrigger interface. // pTrigger->Release(); } } } static VOID InitJobTime(TASK_TRIGGER *pTrigger, INT nSchedule, INT nTimeScheme) { SYSTEMTIME stNow; static INT nMonthDay = 0, // Used to stagger monthly items. nWeekDay = 1, // Used to staggar weekly items. nOnceDay = 1; // Used to staggar once items. INT nDays[] = { TASK_SUNDAY, TASK_MONDAY, TASK_TUESDAY, TASK_WEDNESDAY, TASK_THURSDAY, TASK_FRIDAY, TASK_SATURDAY }; INT nMonths[] = { TASK_JANUARY, TASK_FEBRUARY, TASK_MARCH, TASK_APRIL, TASK_MAY, TASK_JUNE, TASK_JULY, TASK_AUGUST, TASK_SEPTEMBER, TASK_OCTOBER, TASK_NOVEMBER, TASK_DECEMBER }; INT nQuarters[] = { TASK_QUARTER_1, TASK_QUARTER_2, TASK_QUARTER_3, TASK_QUARTER_4 }; // If NULL is passed in for pTrigger, we should reset the // initial values used for scheduling the tasks. // if ( pTrigger == NULL ) { // Reset the static values. // nMonthDay = 0; nWeekDay = 1; nOnceDay = 1; return; } // Init the default trigger structure values. // ZeroMemory(pTrigger, sizeof(TASK_TRIGGER)); pTrigger->cbTriggerSize = sizeof(TASK_TRIGGER); pTrigger->MinutesDuration = 999; // Set the trigger to activate today. // GetLocalTime(&stNow); pTrigger->wBeginMonth = stNow.wMonth; pTrigger->wBeginDay = stNow.wDay; pTrigger->wBeginYear = stNow.wYear; // Set the start hour and minute based on the time scheme. // switch (nTimeScheme) { case IDC_NIGHT: pTrigger->wStartHour = 0; pTrigger->wStartMinute = 0; break; case IDC_DAY: pTrigger->wStartHour = 12; pTrigger->wStartMinute = 00; break; case IDC_EVENING: pTrigger->wStartHour = 20; pTrigger->wStartMinute = 0; break; } // Set the schedule (once, daily, weekly, monthly, bimonthly, quarterly, or yearly). // The day of the week or month is incrimented each time so that once, weekly and // monthly tasks aren't scheduled for the same days. // switch (nSchedule) { case TASK_ONCE: pTrigger->TriggerType = TASK_TIME_TRIGGER_ONCE; IncDate(&(pTrigger->wBeginMonth), &(pTrigger->wBeginDay), &(pTrigger->wBeginYear), nOnceDay++); pTrigger->wStartHour += 2; break; case TASK_DAILY: pTrigger->TriggerType = TASK_TIME_TRIGGER_DAILY; pTrigger->Type.Daily.DaysInterval = 1; break; case TASK_WEEKLY: pTrigger->TriggerType = TASK_TIME_TRIGGER_WEEKLY; pTrigger->Type.Weekly.rgfDaysOfTheWeek = (USHORT)nDays[(((stNow.wDayOfWeek + nWeekDay++) % 7) + 7) % 7]; pTrigger->Type.Weekly.WeeksInterval = 1; pTrigger->wStartMinute += 30; break; case TASK_MONTHLY: case TASK_BIMONTHLY: case TASK_QUARTLY: case TASK_YEARLY: pTrigger->TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE; pTrigger->Type.MonthlyDate.rgfDays = (nMonthDay++ % 28) + 1; pTrigger->wStartHour++; switch (nSchedule) { case TASK_MONTHLY: pTrigger->Type.MonthlyDate.rgfMonths = TASK_WHOLE_YEAR; break; case TASK_BIMONTHLY: pTrigger->Type.MonthlyDate.rgfMonths = ((stNow.wMonth % 2) ? TASK_BIMONTH_EVEN : TASK_BIMONTH_ODD); break; case TASK_QUARTLY: pTrigger->Type.MonthlyDate.rgfMonths = (USHORT)nQuarters[(((stNow.wMonth + 1) % 4) + 4) % 4]; break; case TASK_YEARLY: pTrigger->Type.MonthlyDate.rgfMonths = (USHORT)nMonths[(((stNow.wMonth + 1) % 12) + 12) % 12]; break; } break; } } static VOID IncDate(LPWORD lpwMonth, LPWORD lpwDay, LPWORD lpwYear, INT iDays) { SYSTEMTIME SysTime; FILETIME FileTime; LARGE_INTEGER LargeInt; BOOL bTwoDigit; // Setup the system structure. // ZeroMemory(&SysTime, sizeof(SYSTEMTIME)); SysTime.wMonth = *lpwMonth; SysTime.wDay = *lpwDay; SysTime.wYear = *lpwYear; // Support two digit dates. // if ( bTwoDigit = ( SysTime.wYear < 100 ) ) { if ( SysTime.wYear >= 80 ) SysTime.wYear += 1900; else SysTime.wYear += 2000; } // Convert it to file time. // SystemTimeToFileTime(&SysTime, &FileTime); // Copy it to a large integer so we can add or subtract days. // memcpy(&LargeInt, &FileTime, sizeof(LARGE_INTEGER)); // Add or subtract the days in nanoseconds. // LargeInt.QuadPart += iDays * Int32x32To64(24 * 60 * 60, 1000 * 10000); // Copy it back to the filetime structure. // memcpy(&FileTime, &LargeInt, sizeof(LARGE_INTEGER)); // Convert it back to a systime structure. // FileTimeToSystemTime(&FileTime, &SysTime); // Return supported two digit dates. // if ( bTwoDigit ) { if ( SysTime.wYear <= 2000 ) SysTime.wYear -= 1900; else SysTime.wYear -= 2000; } // Return the new date. // *lpwMonth = SysTime.wMonth; *lpwDay = SysTime.wDay; *lpwYear = SysTime.wYear; } ////////////////////////////////////////////////////////////////////////////// // // INTERNAL: // GetJobFileName() // This routine returns the full path and file name to the job file // specified by the job name passed in. // // ENTRY: // LPTSTR lpJobName // This is the name of the job (as it appears in Task Scheduler) passed in. // // LPTSTR lpJobFileName // This is the buffer that receives the full path and file name of the job // (%WINDIR%\Tasks\lpJobName.JOB). Should be atleast MAX_PATH. // // // EXIT: // BOOL // TRUE - Successfully retrieved all the information and filled in the buffer. // FALSE - Something failed. // ////////////////////////////////////////////////////////////////////////////// static BOOL GetJobFileName(LPTSTR lpJobName, LPTSTR lpJobFileName) { TCHAR szWindowsDir[MAX_PATH]; LPTSTR lpTaskDir, lpJobExt; DWORD dwLength; // Get the windows directory. // if ( GetWindowsDirectory(szWindowsDir, sizeof(szWindowsDir)) == 0 ) return FALSE; // Get rid of the backslash if windows is in the root of a drive. // if ( (dwLength = lstrlen(szWindowsDir)) == 3 ) szWindowsDir[dwLength - 1] = _T('\0'); // Get the task dir from the string resource. // if ( (lpTaskDir = AllocateString(NULL, IDS_TASKDIR)) == NULL ) return FALSE; // Get the job extension from the string resource. // if ( (lpJobExt = AllocateString(NULL, IDS_JOBEXT)) == NULL ) { FREE(lpTaskDir); return FALSE; } // Create the job name with all the data we have. // wsprintf(lpJobFileName, _T("%s%s\\%s%s"), szWindowsDir, lpTaskDir, lpJobName, lpJobExt); FREE(lpJobExt); FREE(lpTaskDir); return TRUE; } /* void ConcatNextRunTime(LPSTR szOrgText, int nItem) { int nLen; SYSTEMTIME stm; char szTemp[128]; DWORD dwFlags; lstrcat(szOrgText, "\n"); // get next run time string dwFlags = ItemData[nItem].dwFlags; dwFlags &= ~TASK_FLAG_DISABLED; // if it's disabled, we can't get run time string pTask[nItem]->SetFlags(dwFlags); // JobRelease will clear it if Cancel finally pTask[nItem]->GetNextRunTime(&stm); if (GetTimeFormat(GetUserDefaultLCID(), TIME_NOSECONDS, &stm, NULL, (LPTSTR)szTemp, 128)) { lstrcat(szTemp, ", "); nLen = lstrlen(szTemp); if (GetDateFormat(GetUserDefaultLCID(), DATE_LONGDATE, &stm, NULL, (LPTSTR)szTemp + nLen, 126-nLen)) lstrcat(szOrgText, szTemp); } } static void taskSetNextDay(TASK_TRIGGER *pTaskTrigger) { if (pTaskTrigger->wBeginMonth == 2 && pTaskTrigger->wBeginDay >= 28) { pTaskTrigger->wBeginMonth++, pTaskTrigger->wBeginDay = 1; } else if (pTaskTrigger->wBeginDay < 30) pTaskTrigger->wBeginDay++; else if (pTaskTrigger->wBeginMonth == 4 || pTaskTrigger->wBeginMonth == 6 || pTaskTrigger->wBeginMonth == 9 || pTaskTrigger->wBeginMonth == 11) { pTaskTrigger->wBeginMonth++, pTaskTrigger->wBeginDay = 1; } else if (pTaskTrigger->wBeginDay < 31) pTaskTrigger->wBeginDay++; else if (pTaskTrigger->wBeginMonth == 12) { pTaskTrigger->wBeginYear++, pTaskTrigger->wBeginMonth = pTaskTrigger->wBeginDay = 1; } else { pTaskTrigger->wBeginMonth++, pTaskTrigger->wBeginDay = 1; } } */ ////////////////////////////////////////////////////////////////////////////// // // INTERNAL: // DeleteOrgJobFile() // This routine deletes the job (if it exists) with the job name passed in. // // ENTRY: // LPTSTR lpJobName - // This is the name of the job (as it appears in Task Scheduler) passed in. // // EXIT: // BOOL // TRUE - Either the file was successfully deleted or it didn't exist. // FALSE - Something failed. // ////////////////////////////////////////////////////////////////////////////// static BOOL DeleteOrgJobFile(LPTSTR lpJobName) { TCHAR szJobFileName[MAX_PATH]; DWORD dwAttr; // First get the full path and file name of // the job file. // if ( !GetJobFileName(lpJobName, szJobFileName) ) return FALSE; // If it doesn't exit, return TRUE. // if ( !(EXIST(szJobFileName)) ) return TRUE; // Make sure the file isn't read only. // if ( (dwAttr = GetFileAttributes(szJobFileName)) & _A_RDONLY ) { dwAttr &= ~_A_RDONLY; SetFileAttributes(szJobFileName, dwAttr); } // Return the success or failure of DeleteFile(). // return DeleteFile(szJobFileName); } /* int GetTimeScheme() { int i, nTimeScheme; ITaskTrigger *pTrigger = NULL; TASK_TRIGGER TaskTrigger, SchemeTrigger[ITEM_NUM]; if (g_bEnableDefaultScheme == FALSE) return g_nTimeScheme; // check scheme by scheme for (nTimeScheme = IDC_NIGHT; nTimeScheme <= IDC_EVENING; nTimeScheme++) { for (i = TASK_FIRST; i <= TASK_LAST; i++) { if (!ItemData[i].bNeeded) continue; //InitJobTime(i, nTimeScheme, &SchemeTrigger[i]); } for (i = TASK_FIRST; i <= TASK_LAST; i++) { if (!ItemData[i].bNeeded) continue; if (!GetTaskTrigger(pTask[i], &TaskTrigger)) break; if (memcmp((const void*)&TaskTrigger, (const void*)&SchemeTrigger[i], sizeof(TASK_TRIGGER))) break; } if (i == (TASK_LAST + 1)) // all the item match this scheme setting return nTimeScheme; } return IDC_CUSTOM; } */ static BOOL GetTaskTrigger(ITask *pJob, TASK_TRIGGER *pTaskTrigger) { ITaskTrigger *pTrigger = NULL; if (pJob->GetTrigger((WORD)0, &pTrigger) != S_OK) return FALSE; ZeroMemory(pTaskTrigger, sizeof(TASK_TRIGGER)); pTrigger->GetTrigger(pTaskTrigger); pTrigger->Release(); return TRUE; }