//+---------------------------------------------------------------------------- // // Scheduling Agent Service // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996. // // File: atconv.cxx // // Classes: None. // // Functions: ConvertAtJobsToTasks // // History: 13-Jun-96 EricB Created. // //----------------------------------------------------------------------------- #include "..\pch\headers.hxx" #pragma hdrstop #include #include #include "..\inc\debug.hxx" // // The constants and types below taken from net\svcdlls\at\server\at.h // #define AT_REGISTRY_PATH L"System\\CurrentControlSet\\Services\\Schedule" #define AT_SCHEDULE_NAME L"Schedule" #define AT_COMMAND_NAME L"Command" #define MAXIMUM_COMMAND_LENGTH (MAX_PATH - 1) // == 259, cmd.exe uses this #define MAXIMUM_JOB_TIME (24 * 60 * 60 * 1000 - 1) #define DAYS_OF_WEEK 0x7F // 7 bits for 7 days #define DAYS_OF_MONTH 0x7FFFFFFF // 31 bits for 31 days #define AT_KEY_BUF_LEN 20 // 9 would suffice, but this is safer typedef struct _AT_SCHEDULE { DWORD JobTime; // time of day to run, in seconds from midnight DWORD DaysOfMonth; // bitmask for days of month to run UCHAR DaysOfWeek; // bitmask for days of week to run UCHAR Flags; // see lmat.h WORD Reserved; // padding, since registry pads them as well } AT_SCHEDULE; //+---------------------------------------------------------------------------- // // Function: ConvertAtJobsToTasks // // Synopsis: At setup time, read the AT service jobs out of the registry // and convert them to Scheduling Agent Tasks. // //----------------------------------------------------------------------------- STDAPI_(void) ConvertAtJobsToTasks(void) { struct KEYNAME { KEYNAME * pNext; WCHAR wszName[AT_KEY_BUF_LEN]; }; CSchedule * pSch = new CSchedule; if (pSch == NULL) { ERR_OUT("ConvertAtJobsToTasks, new pSch", E_OUTOFMEMORY); return; } HRESULT hr = pSch->Init(); if (FAILED(hr)) { pSch->Release(); ERR_OUT("ConvertAtJobsToTasks, pSch->Init", hr); return; } HKEY hKeySvc, hKey; DWORD index; WCHAR wszNameBuffer[AT_KEY_BUF_LEN]; FILETIME lastWriteTime; WCHAR wszCommand[MAXIMUM_COMMAND_LENGTH + 1]; AT_SCHEDULE Schedule; DWORD Length; DWORD type; DWORD NameSize; DWORD CommandSize; KEYNAME * pDeleteList = NULL; long lRet; // // Open the AT service registry tree. // lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AT_REGISTRY_PATH, 0, KEY_READ, &hKeySvc); if (lRet != ERROR_SUCCESS) { ERR_OUT("ConvertAtJobsToTasks: open hKeySvc", lRet); pSch->Release(); return; } for (index = 0; ; index++) { // // Regedit can sometimes display other keys in addition to keys // found here. Also, it often fails to display last character in // the Command and after a refresh it may not display some of the // spurious keys. // Length = sizeof(wszNameBuffer) / sizeof(wszNameBuffer[0]); lRet = RegEnumKeyEx(hKeySvc, index, wszNameBuffer, // lpName &Length, // lpcbName 0, // lpReserved NULL, // lpClass NULL, // lpcbClass &lastWriteTime); if (lRet != ERROR_SUCCESS && lRet != ERROR_MORE_DATA) { if (lRet != ERROR_NO_MORE_ITEMS) { ERR_OUT("ConvertAtJobsToTasks: RegEnumKeyEx", lRet); } // // The only exit point from this loop // break; } // // Length returned is the number of characters in a UNICODE string // representing the key name (not counting the terminating NULL // character which is also supplied). // NameSize = (Length + 1) * sizeof(WCHAR); lRet = RegOpenKeyEx(hKeySvc, wszNameBuffer, 0, KEY_READ, &hKey); if (lRet != ERROR_SUCCESS) { ERR_OUT("ConvertAtJobsToTasks: RegOpenKeyEx", lRet); continue; } Length = sizeof(Schedule); lRet = RegQueryValueEx(hKey, AT_SCHEDULE_NAME, NULL, &type, (LPBYTE)&Schedule, &Length); if (lRet != ERROR_SUCCESS) { ERR_OUT("ConvertAtJobsToTasks: RegQueryValueEx(AT_SCHEDULE_NAME)", lRet); RegCloseKey(hKey); continue; } if (type != REG_BINARY || Length != sizeof(AT_SCHEDULE) || (Schedule.DaysOfWeek & ~DAYS_OF_WEEK) != 0 || (Schedule.DaysOfMonth & ~DAYS_OF_MONTH) != 0 || Schedule.JobTime >= MAXIMUM_JOB_TIME ) { schDebugOut((DEB_ERROR,"ConvertAtJobsToTasks: RegQueryValueEx invalid data: " "type=%lu, Length=%lu, DOW=%#x, DOM=%#lx, Time=%lu\n", type, Length, Schedule.DaysOfWeek, Schedule.DaysOfMonth, Schedule.JobTime)); RegCloseKey(hKey); continue; } Length = sizeof(wszCommand); lRet = RegQueryValueEx(hKey, AT_COMMAND_NAME, NULL, &type, (LPBYTE)wszCommand, &Length); RegCloseKey(hKey); if (lRet != ERROR_SUCCESS) { ERR_OUT("ConvertAtJobsToTasks: RegQueryValueEx(AT_COMMAND_NAME)", lRet); continue; } if (type != REG_SZ) { ERR_OUT("ConvertAtJobsToTasks: Command is not of REG_SZ type", 0); continue; } AT_INFO At; At.Command = wszCommand; At.JobTime = Schedule.JobTime; At.DaysOfMonth = Schedule.DaysOfMonth; At.DaysOfWeek = Schedule.DaysOfWeek; At.Flags = Schedule.Flags; hr = pSch->AddAtJob(At, NULL); if (SUCCEEDED(hr)) { // // If the job was successfully converted, then add it to the // list of jobs to delete from the registry. Don't delete it // right away, because that would mess up the operation of // RegEnumKeyEx. // KEYNAME * pKey = new KEYNAME; if (pKey == NULL) { ERR_OUT("ConvertAtJobsToTasks: new KEYNAME", GetLastError()); RegDeleteKey(hKeySvc, wszNameBuffer); break; } pKey->pNext = pDeleteList; pDeleteList = pKey; StringCchCopy(pKey->wszName, AT_KEY_BUF_LEN, wszNameBuffer); } #if DBG == 1 else { ERR_OUT("ConvertAtJobsToTasks: AddAtJob", hr); } #endif } // // Delete the reg keys for all jobs that were successfully converted // KEYNAME * pNext; for ( ; pDeleteList != NULL; pDeleteList = pNext) { RegDeleteKey(hKeySvc, pDeleteList->wszName); pNext = pDeleteList->pNext; delete pDeleteList; } RegCloseKey(hKeySvc); pSch->Release(); return; }