windows-nt/Source/XPSP1/NT/shell/osshell/themes/themesw/schedule.cpp

1626 lines
46 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// File: schedule.cpp
//
// Contents: Functions needed to start, query, add, remove tasks
// in Task Scheduler
//
// Microsoft Desktop Themes for Windows
// Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
#include <wchar.h>
#include <windows.h>
#include <mbctype.h>
#include <objbase.h>
#include <initguid.h>
#include <mstask.h>
#include <msterr.h>
#include "frost.h"
#define MSG_BOX_TSERR(hw,msg) MessageBox(hw, msg, szThemeName,\
MB_OK | MB_ICONERROR | MB_APPLMODAL)
#define SCHED_CLASS TEXT("SAGEWINDOWCLASS")
#define SCHED_TITLE TEXT("SYSTEM AGENT COM WINDOW")
#define SCHED_SERVICE_APP_NAME TEXT("mstask.exe")
#define SCHED_SERVICE_NAME TEXT("Schedule")
#define EVERY_MONTH (TASK_JANUARY | TASK_FEBRUARY | TASK_MARCH | TASK_APRIL |\
TASK_MAY | TASK_JUNE | TASK_JULY | TASK_AUGUST |\
TASK_SEPTEMBER | TASK_OCTOBER | TASK_NOVEMBER |\
TASK_DECEMBER)
//+--------------------------------------------------------------------------
// Global variables defined in GLOBAL.H for compat. with C sources
//---------------------------------------------------------------------------
extern "C" HWND hWndApp = NULL;
extern "C" HINSTANCE hInstApp = NULL;
//+--------------------------------------------------------------------------
// Global variables for use in SCHEDULE.CPP only
//---------------------------------------------------------------------------
ITaskScheduler *g_pITaskScheduler = NULL;
TCHAR szRunServices[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices");
TCHAR szScheduler[] = TEXT("SchedulingAgent");
TCHAR szMSTask[] = TEXT("mstask.exe");
TCHAR szUserName[MAX_PATH];
TCHAR szPassword[MAX_PATH];
//+--------------------------------------------------------------------------
// Function Prototypes
//---------------------------------------------------------------------------
HRESULT Init(void);
void Cleanup(void);
extern "C" BOOL IsTaskSchedulerRunning();
extern "C" BOOL StartTaskScheduler(BOOL);
extern "C" BOOL IsThemesScheduled();
extern "C" BOOL AddThemesTask(LPTSTR, BOOL);
extern "C" BOOL DeleteThemesTask();
extern "C" BOOL HandDeleteThemesTask();
extern "C" BOOL IsPlatformNT();
extern "C" BOOL GetCurrentUser(LPTSTR, DWORD, LPTSTR, DWORD, LPTSTR, DWORD);
extern "C" BOOL GetTextualSid(PSID, LPTSTR, LPDWORD);
extern "C" VOID BuildNTJobName(LPTSTR);
extern "C" BOOL IsUserAdmin();
//+--------------------------------------------------------------------------
//
// Function: PasswordDlgProc()
//
// Synopsis: WINNT only -- prompts user for name and password.
//
// Arguments: none (void)
//
//---------------------------------------------------------------------------
INT_PTR CALLBACK PasswordDlgProc(HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
TCHAR szPWConfirm[MAX_PATH];
TCHAR szErrMsg[MAX_PATH];
TCHAR szThemeName[MAX_STRLEN]; // Used for msgbox title
DWORD dwSize = 0;
TCHAR szProfile[MAX_PATH];
switch(uMsg)
{
case WM_INITDIALOG:
if (GetCurrentUser(szPassword, /* Actually user name */
ARRAYSIZE(szPassword),
szUserName, /* Actually domain name */
ARRAYSIZE(szUserName),
szProfile,
ARRAYSIZE(szProfile)))
{
// GetCurrentUser succeeded so build the domain\user
//
// Remember these variable names are bogus --
// szUserName is actually the domain name
// szPassword is actually the user name
//
if (szPassword[0]) lstrcat(szUserName, TEXT("\\"));
lstrcat(szUserName, szPassword);
}
else
{
// GetCurrentUser failed so do this as last resort
dwSize = ARRAYSIZE(szUserName);
GetUserName(szUserName, &dwSize);
}
*szPassword = 0;
SetDlgItemText(hDlg, EDIT_USER, szUserName);
SetFocus(GetDlgItem(hDlg, EDIT_PW));
return FALSE; // Return false to keep focus on PW control
break;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
GetDlgItemText(hDlg, EDIT_USER, szUserName, MAX_PATH);
GetDlgItemText(hDlg, EDIT_PW, szPassword, MAX_PATH);
GetDlgItemText(hDlg, EDIT_PWCONFIRM, szPWConfirm, MAX_PATH);
if (lstrcmp(szPassword, szPWConfirm))
{
// PW and PWCONFIRM don't match
LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
LoadString(hInstApp, STR_PW_NOMATCH, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
SetDlgItemText(hDlg, EDIT_PW, TEXT("\0"));
SetDlgItemText(hDlg, EDIT_PWCONFIRM, TEXT("\0"));
SetActiveWindow(GetDlgItem(hDlg, EDIT_PW));
SetFocus(GetDlgItem(hDlg, EDIT_PW));
break;
}
else
{
EndDialog(hDlg,1);
break;
}
case IDCANCEL:
szUserName[0] = TEXT('\0');
szPassword[0] = TEXT('\0');
EndDialog(hDlg, 0);
break;
}
break;
default:
return FALSE;
} // switch uMsg
return TRUE;
} // PasswordDlgProc
//+--------------------------------------------------------------------------
//
// Function: IsPlatformNT()
//
// Synopsis: Checks to see if the os is NT or not.
//
// Arguments: none (void)
//
// Returns: TRUE if NT, FALSE if not.
//
//---------------------------------------------------------------------------
extern "C" BOOL IsPlatformNT()
{
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
// Determine what version of OS we are running on.
GetVersionEx(&osver);
if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
return TRUE;
else
return FALSE;
}
//+--------------------------------------------------------------------------
//
// Function: IsTaskSchedulerRunning()
//
// Synopsis: Looks for TS window to determince TS is running.
//
// Arguments: none (void)
//
// Returns: TRUE if running, FALSE if not.
//
//---------------------------------------------------------------------------
extern "C" BOOL IsTaskSchedulerRunning()
{
HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
if (hwnd == NULL)
{
//MessageBox(hWndApp, TEXT("TS is not running"), TEXT("Desktop Themes"), MB_OK | MB_APPLMODAL);
return FALSE;
}
else
{
//MessageBox(hWndApp, TEXT("TS is running"), TEXT("Desktop Themes"), MB_OK | MB_APPLMODAL);
return TRUE;
}
}
//---------------------------------------------------------------------------
// Function: StartTaskScheduler
// Synopsis: Start the task scheduler service if it isn't already running.
// Arguments: bPrompt -- TRUE == prompt user before starting.
// FALSE == just start it, don't prompt user.
// Returns: TRUE if successful, FALSE if not.
// Notes: This function works in Win9x only.
// If the service is running but paused, does nothing.
//---------------------------------------------------------------------------
extern "C" BOOL StartTaskScheduler(BOOL bPrompt)
{
STARTUPINFO sui;
PROCESS_INFORMATION pi;
TCHAR szApp[MAX_PATH];
LPTSTR pszPath;
DWORD dwRet;
BOOL fRet;
TCHAR szErrMsg[MAX_PATH];
TCHAR szThemeName[MAX_STRLEN]; // Used for msgbox title
int MBChoice; // User's reply to Yes/No dialog
DWORD dwDisposition;
HKEY hKey;
LONG lret;
LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
if (hwnd != NULL) {
// It is already running.
return TRUE;
}
// If specified, prompt user before attempting to start
// Task Scheduler.
if (bPrompt) {
LoadString(hInstApp, STR_ERRTSNOTRUN, szErrMsg, MAX_PATH);
MBChoice = MessageBox(hWndApp, szErrMsg, szThemeName,
MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL);
// Did user opt to NOT start task scheduler?
if (IDYES != MBChoice) return FALSE;
}
if (!IsPlatformNT()) {
// Start the Win9x version of TaskScheduler.
// Execute the task scheduler process.
ZeroMemory(&sui, sizeof(sui));
sui.cb = sizeof(STARTUPINFO);
dwRet = SearchPath(NULL,
SCHED_SERVICE_APP_NAME,
NULL,
MAX_PATH,
szApp,
&pszPath);
if (dwRet == 0) {
LoadString(hInstApp, STR_ERRTSNOTFOUND, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
fRet = CreateProcess(szApp,
NULL,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&sui,
&pi);
if (fRet == 0) {
LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// Assume that MSTASK.EXE was successfully started. We need to
// add mstask.exe to the RunServices branch of the registry.
hKey = NULL;
lret = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
szRunServices,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&dwDisposition);
if (lret == ERROR_SUCCESS) {
// RegDeleteValue(hKey, szScheduler);
lret = RegSetValueEx(hKey,
szScheduler,
0,
REG_SZ,
(CONST BYTE *)szMSTask,
SZSIZEINBYTES(szMSTask));
}
if (hKey) RegCloseKey(hKey);
return TRUE;
}
else
{
// If not Win9x then start the NT version as a TaskScheduler service.
SC_HANDLE hSC = NULL;
SC_HANDLE hSchSvc = NULL;
// Does the user have administrative privileges? If not, the
// user can't start TS.
if (!IsUserAdmin())
{
LoadString(hInstApp, STR_ERRTSNOTADMIN, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hSC == NULL)
{
return FALSE;
// NEED TO ADD ERROR DIALOG HERE
// return GetLastError();
}
hSchSvc = OpenService(hSC,
SCHED_SERVICE_NAME,
SERVICE_START | SERVICE_QUERY_STATUS);
CloseServiceHandle(hSC);
if (hSchSvc == NULL)
{
LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
SERVICE_STATUS SvcStatus;
if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
{
CloseServiceHandle(hSchSvc);
LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
{
// The service is already running.
CloseServiceHandle(hSchSvc);
return TRUE;
}
if (StartService(hSchSvc, 0, NULL) == FALSE)
{
CloseServiceHandle(hSchSvc);
LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
MessageBox(hWndApp, szErrMsg, szThemeName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
return FALSE;
}
CloseServiceHandle(hSchSvc);
return TRUE;
}
} // END StartTaskScheduler()
//+--------------------------------------------------------------------------
//
// Function: Init()
//
// Synopsis: Called to initialize and instantiate a task
// scheduler object.
//
// Arguments: none (void)
//
// Returns: HRESULT indicating success or failure. S_OK on success.
//
// Side effect: Sets global pointer g_pITaskScheduler, for use in other
// functions.
//
//---------------------------------------------------------------------------
HRESULT Init()
{
HRESULT hr = S_OK;
// Bring in the library
hr = CoInitialize(NULL);
if (FAILED(hr))
{
return hr;
}
// Create the pointer to Task Scheduler object
// CLSID from the header file mstask.h
hr = CoCreateInstance(
CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &g_pITaskScheduler);
// Should we fail, unload the library
if (FAILED(hr))
{
CoUninitialize();
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: Cleanup()
//
// Synopsis: Called to clean up OLE, memory, etc. before termination
//
// Arguments: none (void)
//
// Returns: nothing (void)
//
// Side effect: Cancels the global pointer g_pITaskScheduler.
//
//---------------------------------------------------------------------------
void Cleanup()
{
if (g_pITaskScheduler)
{
g_pITaskScheduler->Release();
g_pITaskScheduler = NULL;
}
// Unload the library, now that our pointer is freed.
CoUninitialize();
return;
}
//+--------------------------------------------------------------------------
//
// Function: IsThemesScheduled()
//
// Synopsis: Enumerates tasks and returns TRUE if Themes.job exists.
// Returns FALSE if it does not.
//
// Arguments: none (void). Requires g_pITaskScheduler.
//
// Returns: TRUE if Themes.job exists, else FALSE
//
//---------------------------------------------------------------------------
extern "C" BOOL IsThemesScheduled()
{
HRESULT hr = S_OK, hrLoop = S_OK;
IEnumWorkItems *pIEnumWorkItems;
IUnknown *pIU;
ITask *pITask;
ULONG ulTasksToGet = 1, ulActualTasksRetrieved = 0;
LPWSTR *rgpwszNames;
TCHAR szDefaultJobName[MAX_PATH];
BOOL bResult;
UINT uCodePage;
#ifndef UNICODE
CHAR szJobNameA[MAX_PATH];
#endif
// For protection
g_pITaskScheduler = NULL;
// String conversion initialization
uCodePage = _getmbcp();
// Attempt to initialize OLE and fill in the global g_pITaskScheduler
hr = Init();
if (FAILED(hr))
{
return FALSE;
}
// Get the default name for a Themes task
LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
// If this is NT we need to append the user profile name onto the
// end of this task.
if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
//
// Get an enumeration pointer, using ITaskScheduler::Enum
//
hr = g_pITaskScheduler->Enum(&pIEnumWorkItems);
if (FAILED(hr))
{
// LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
// MSG_BOX_TSERR(hWndApp, szErrMsg);
Cleanup();
return FALSE;
}
bResult = FALSE;
do
{
// Get a single work item, using IEnumWorkItems::Next
hrLoop = pIEnumWorkItems->Next(ulTasksToGet, &rgpwszNames,
&ulActualTasksRetrieved);
if (hrLoop == S_FALSE)
{
// There are no more waiting tasks to look at
break;
}
// Attach to the work item, using ITaskScheduler::Activate
hr = g_pITaskScheduler->Activate(rgpwszNames[0], IID_ITask, &pIU);
if (FAILED(hr))
{
// LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
// MSG_BOX_TSERR(hWndApp, szErrMsg);
bResult = FALSE;
break;
}
// QI pIU for pITask
hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
pIU->Release();
pIU = NULL;
if (FAILED(hr))
{
// LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
// MSG_BOX_TSERR(hWndApp, szErrMsg);
bResult = FALSE;
break;
}
// Compare task name
#ifndef UNICODE
// No UNICODE so we need to convert the wide string returned
// by ITask into an ANSI string.
WideCharToMultiByte(uCodePage, 0, rgpwszNames[0], -1,
szJobNameA, MAX_PATH, NULL, NULL);
// MessageBox(hWndApp, szJobNameA, szThemeName,
// MB_OK | MB_APPLMODAL);
if (!lstrcmp(szJobNameA, szDefaultJobName)) bResult = TRUE;
#else
// We're living in a UNICODE world so no need to convert
// the string from ITask.
// MessageBox(hWndApp, rgpwszNames[0], szThemeName,
// MB_OK | MB_APPLMODAL);
if (!lstrcmp(rgpwszNames[0], szDefaultJobName)) bResult = TRUE;
#endif
// Clean up each element in the array of job names, then
// clean up the final array.
CoTaskMemFree(rgpwszNames[0]);
CoTaskMemFree(rgpwszNames);
// Free the ITask pointer
pITask->Release();
} while(!bResult);
// Release the enumeration pointer
pITask = NULL;
pIEnumWorkItems->Release();
pIEnumWorkItems = NULL;
Cleanup();
return bResult; //
}
//+--------------------------------------------------------------------------
//
// Function: DeleteThemesTask()
//
// Synopsis: Deletes Themes task from Task Scheduler.
//
// Returns: TRUE if OK, FALSE if FAIL.
//
//---------------------------------------------------------------------------
extern "C" BOOL DeleteThemesTask()
{
HRESULT hr = S_OK;
UINT uCodePage;
TCHAR szDefaultJobName[MAX_PATH];
#ifndef UNICODE
WCHAR szJobNameW[MAX_PATH];
#endif
// String conversion initialization
uCodePage = _getmbcp();
// For protection
g_pITaskScheduler = NULL;
// Attempt to initialize OLE and fill in the global g_pITaskScheduler
hr = Init();
if (FAILED(hr))
{
// LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
// MSG_BOX_TSERR(hWndApp, szErrMsg);
return FALSE;
}
// Get the default name for a Themes task
LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
// If this is NT we need to append the user profile name onto the
// end of this task.
if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
#ifndef UNICODE
// No UNICODE so convert the string to WCHAR format to
// please the TS interface
MultiByteToWideChar(uCodePage, 0, szDefaultJobName, -1,
szJobNameW, MAX_PATH);
// Delete it
hr = g_pITaskScheduler->Delete(szJobNameW);
#else // UNICODE
// We're UNICODE so we don't need to convert the string before
// calling TS
hr = g_pITaskScheduler->Delete(szDefaultJobName);
#endif
Cleanup();
return TRUE; // Returns TRUE regardless of hr value.
}
//+--------------------------------------------------------------------------
//
// Function: AddThemesTask()
//
// Synopsis: Adds a new work item to the Scheduled Tasks folder.
//
// Arguments: lpwszThemesExe - fully qualified path to Themes.exe.
// bShowErrors - if TRUE, ATT shows error dialogs else
// it fails silently.
//
// Returns: TRUE if successful, FALSE if not.
//
//---------------------------------------------------------------------------
extern "C" BOOL AddThemesTask(LPTSTR lpszThemesExe, BOOL bShowErrors)
{
HRESULT hr = S_OK;
IUnknown *pIU;
IPersistFile *pIPF;
ITask *pITask;
ITaskTrigger *pITaskTrig;
DWORD dwTaskFlags, dwTrigFlags;
WORD wTrigNumber;
TASK_TRIGGER TaskTrig;
UINT uCodePage;
//TCHAR szUserName[MAX_PATH];
//TCHAR szPassword[MAX_PATH];
WCHAR szRotateCommandW[] = L"/r";
TCHAR szDefaultJobName[MAX_PATH];
TCHAR szJobComment[MAX_PATH];
#ifndef UNICODE
WCHAR szUserNameW[MAX_PATH];
WCHAR szPasswordW[MAX_PATH];
WCHAR szThemesExeW[MAX_PATH];
WCHAR szJobNameW[MAX_PATH];
WCHAR szJobCommentW[MAX_PATH];
#endif
SYSTEMTIME LocalTime;
TCHAR szErrMsg[MAX_PATH];
TCHAR szThemeName[MAX_STRLEN]; // msg box title
HKEY hKey;
DWORD dwDisposition;
LONG lret;
INT_PTR iResult;
LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
LoadString(hInstApp, STR_JOB_COMMENT, szJobComment, MAX_PATH);
// If this is NT we need to append the user profile name onto the
// end of this task.
if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
// String conversion initialization
uCodePage = _getmbcp();
// For protection
g_pITaskScheduler = NULL;
// Attempt to initialize OLE and fill in the global g_pITaskScheduler
hr = Init();
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
return FALSE;
}
// Add the task. Most likely failure is that work item already exists.
// Uses ITaskScheduler::NewWorkItem
#ifndef UNICODE
// No UNICODE so convert string to wide before adding task
MultiByteToWideChar(uCodePage, 0, szDefaultJobName, -1,
szJobNameW, MAX_PATH);
hr = g_pITaskScheduler->NewWorkItem(szJobNameW,
CLSID_CTask,
IID_ITask,
&pIU);
#else
// UNICODE, so no need to convert string to WIDE before adding task
hr = g_pITaskScheduler->NewWorkItem(szDefaultJobName,
CLSID_CTask,
IID_ITask,
&pIU);
#endif
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
Cleanup();
return FALSE;
}
// We now have an IUnknown pointer. This is queried for an ITask
// pointer on the work item we just added.
hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pIU->Release();
Cleanup();
return FALSE;
}
// Cleanup pIUnknown, as we are done with it.
pIU->Release();
pIU = NULL;
//
// If this is for NT we need to get and set the user account
// information. ITask::SetAccountInformation
//
if (IsPlatformNT())
{
szUserName[0] = TEXT('\0'); // global user name string
szPassword[0] = TEXT('\0'); // global password string
// Prompt for the user name and password
//
// Password dialog returns:
// -1 if DialogBox() fails
// 0 if user cancels
// 1 if PW entered OK
iResult = 0;
iResult = DialogBox(hInstApp,
MAKEINTRESOURCE(DLG_PASSWORD),
hWndApp,
PasswordDlgProc);
if (iResult < 1)
{
// Either the password dialog failed or the user Canceled
// it so bail out.
pITask->Release();
Cleanup();
return FALSE;
}
#ifndef UNICODE
// No UNICODE so we need to convert from ANSI to WCHAR before
// calling SetAccountInformation
MultiByteToWideChar(uCodePage, 0, szUserName, -1,
szUserNameW, MAX_PATH);
MultiByteToWideChar(uCodePage, 0, szPassword, -1,
szPasswordW, MAX_PATH);
hr = pITask->SetAccountInformation(szUserNameW, szPasswordW);
#else
// UNICODE so no need to convert strings
hr = pITask->SetAccountInformation(szUserName, szPassword);
#endif // UNICODE
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
} // IsPlatformNT
// Set command name with ITask::SetApplicationName
#ifndef UNICODE
// No UNICODE so need to convert string to WIDE
MultiByteToWideChar(uCodePage, 0, lpszThemesExe, -1,
szThemesExeW, MAX_PATH);
hr = pITask->SetApplicationName(szThemesExeW);
#else
// UNICODE so no need to convert string
hr = pITask->SetApplicationName(lpszThemesExe);
#endif
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
// Set task parameters with ITask::SetParameters
hr = pITask->SetParameters(szRotateCommandW);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
// Set the comment, so we know how this job got there
// Uses ITask::SetComment
#ifndef UNICODE
// No UNICODE so convert to WIDE
MultiByteToWideChar(uCodePage, 0, szJobComment, -1,
szJobCommentW, MAX_PATH);
hr = pITask->SetComment(szJobCommentW);
#else
// UNICODE so no need to convert string
hr = pITask->SetComment(szJobComment);
#endif
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
// Set the flags on the task object
// Use ITask::SetFlags
dwTaskFlags = NULL;
hr = pITask->SetFlags(dwTaskFlags);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
// Now, create a trigger to run the task at our specified time.
// Uses ITask::CreateTrigger()
hr = pITask->CreateTrigger(&wTrigNumber, &pITaskTrig);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITask->Release();
Cleanup();
return FALSE;
}
// Now, fill in the trigger as necessary.
GetLocalTime(&LocalTime);
if (12 == LocalTime.wMonth) {
LocalTime.wMonth = 1;
LocalTime.wYear++;
}
else LocalTime.wMonth++;
dwTrigFlags = 0;
TaskTrig.cbTriggerSize = sizeof(TASK_TRIGGER);
TaskTrig.Reserved1 = 0;
TaskTrig.wBeginYear = LocalTime.wYear;
TaskTrig.wBeginMonth = LocalTime.wMonth;
TaskTrig.wBeginDay = 1;
TaskTrig.wEndYear = 0;
TaskTrig.wEndMonth = 0;
TaskTrig.wEndDay = 0;
TaskTrig.wStartHour = 14;
TaskTrig.wStartMinute = 0;
TaskTrig.MinutesDuration = 0;
TaskTrig.MinutesInterval = 0;
TaskTrig.rgFlags = dwTrigFlags;
TaskTrig.TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE;
TaskTrig.Type.MonthlyDate.rgfDays = 1;
TaskTrig.Type.MonthlyDate.rgfMonths = EVERY_MONTH;
TaskTrig.wRandomMinutesInterval = 0;
TaskTrig.Reserved2 = 0;
// Add this trigger to the task using ITaskTrigger::SetTrigger
hr = pITaskTrig->SetTrigger(&TaskTrig);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITaskTrig->Release();
pITask->Release();
Cleanup();
return FALSE;
}
// Make the changes permanent
// Requires using IPersistFile::Save()
hr = pITask->QueryInterface(IID_IPersistFile, (void **) &pIPF);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITaskTrig->Release();
pITask->Release();
Cleanup();
return FALSE;
}
hr = pIPF->Save(NULL, FALSE);
if (FAILED(hr))
{
if (bShowErrors) {
LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
MSG_BOX_TSERR(hWndApp, szErrMsg);
}
pITaskTrig->Release();
pITask->Release();
pIPF->Release();
Cleanup();
return FALSE;
}
// We no longer need ITask
pITask->Release();
pITask = NULL;
// Done with ITaskTrigger pointer
pITaskTrig->Release();
pITaskTrig = NULL;
// Done with IPersistFile
pIPF->Release();
pIPF = NULL;
Cleanup();
// Finally -- we have successfully added the task but we need to
// make sure that Task Scheduler is in the RunServices branch of
// the registry so it will start every time.
hKey = NULL;
lret = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
szRunServices,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&dwDisposition);
if (lret == ERROR_SUCCESS) {
// RegDeleteValue(hKey, szScheduler);
lret = RegSetValueEx(hKey,
szScheduler,
0,
REG_SZ,
(CONST BYTE *)szMSTask,
(SZSIZEINBYTES(szMSTask) + 1));
}
if (hKey) RegCloseKey(hKey);
return TRUE;
}
extern "C" BOOL HandDeleteThemesTask()
{
TCHAR szJobFile[MAX_PATH]; // Full path to %windir%\Tasks\Themes.job
TCHAR szDefaultJobName[MAX_PATH];
if (!GetWindowsDirectory(szJobFile, MAX_PATH)) return FALSE;
lstrcat(szJobFile, TEXT("\\Tasks\\\0"));
LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
// If this is NT we need to append the user profile name onto the
// end of this task.
if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
lstrcat(szJobFile, szDefaultJobName);
DeleteFile(szJobFile);
return TRUE;
}
//---------------------------------------------------------------------------
// GetUserToken - Gets the current process's user token and returns
// it. It can later be free'd with LocalFree.
//---------------------------------------------------------------------------
PTOKEN_USER GetUserToken(HANDLE hUser)
{
PTOKEN_USER pUser;
DWORD dwSize = 64;
HANDLE hToClose = NULL;
if (hUser == NULL)
{
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser);
hToClose = hUser;
}
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwSize);
if (pUser)
{
DWORD dwNewSize;
BOOL fOk = GetTokenInformation(hUser, TokenUser, pUser, dwSize, &dwNewSize);
if (!fOk && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
LocalFree((HLOCAL)pUser);
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwNewSize);
if (pUser)
{
fOk = GetTokenInformation( hUser, TokenUser, pUser, dwNewSize, &dwNewSize);
}
}
if (!fOk)
{
LocalFree((HLOCAL)pUser);
pUser = NULL;
}
}
if (hToClose)
CloseHandle(hToClose);
return pUser;
}
//----------------------------------------------------------------------------
// GetCurrentUser - Fills in a buffer with the unique name that we are using
// for the currently logged on user. On NT, this name is
// used for the name of the profile directory and for the
// name of the per-user recycle bin directory on a security
// aware drive.
//
// Parameters:
// lpAccountName -- buffer to receive user account name
// lpDomainName -- buffer to receive domain name
// lpProfilePath -- receives fully qualified path to user's
// profile directory. If the caller does
// not want the profile path NULL may be
// passed in for this parameter.
//----------------------------------------------------------------------------
extern "C" BOOL GetCurrentUser(LPTSTR lpAccountName, DWORD cchAcctSize,
LPTSTR lpDomainName, DWORD cchDomSize,
LPTSTR lpProfilePath, DWORD cchProfSize)
{
PTOKEN_USER pUser;
LPTSTR pTextSid = 0;
DWORD cbBytes;
SID_NAME_USE SNU;
HANDLE hUser;
// Take the easy outs -- no NULL parms for first four.
if (!lpAccountName || !lpDomainName || !&cchAcctSize || !&cchDomSize) return FALSE;
// Initialize these strings to NULL.
*lpAccountName = 0;
*lpDomainName = 0;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser))
{
return FALSE;
}
pUser = GetUserToken(hUser);
CloseHandle(hUser);
if (!pUser)
return FALSE;
if (!IsValidSid(pUser->User.Sid))
{
LocalFree(pUser);
return FALSE;
}
if (!LookupAccountSid(NULL,
pUser->User.Sid,
lpAccountName,
&cchAcctSize,
lpDomainName,
&cchDomSize,
&SNU))
{
// LookupAccountSid failed
LocalFree(pUser);
return FALSE;
}
// Does the caller want the profile path?
if (!lpProfilePath)
{
// No, so cleanup and hit the road.
LocalFree(pUser);
return TRUE;
}
// Have the Account and Domain Name. Next we need to get
// a text based SID so we can lookup the profile path in
// the registry.
// First let's find out how big a buffer we need for the
// text Sid.
*lpProfilePath = 0;
cbBytes = 0;
if ((!GetTextualSid(pUser->User.Sid, pTextSid, &cbBytes)) &&
(ERROR_INSUFFICIENT_BUFFER == GetLastError()))
{
pTextSid = (LPTSTR)LocalAlloc(LPTR, cbBytes);
if (!pTextSid)
{
LocalFree(pUser);
return FALSE;
}
if (!GetTextualSid(pUser->User.Sid, pTextSid, &cbBytes))
{
LocalFree(pUser);
return FALSE;
}
}
else
{
// Failed to get a text SID so we're outta here.
LocalFree((HLOCAL)pUser);
return FALSE;
}
// OK, now we should have a text-based SID. Used this to find
// the profilepath in the registry.
if (pTextSid)
{
HKEY hkeyProfileList;
// Open the registry and find the appropriate name
LONG lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), 0,
KEY_READ, &hkeyProfileList);
if (lStatus == ERROR_SUCCESS)
{
HKEY hkeyUser;
lStatus = RegOpenKeyEx(hkeyProfileList, pTextSid, 0, KEY_READ, &hkeyUser);
if (lStatus == ERROR_SUCCESS)
{
DWORD dwType;
cbBytes = (cchProfSize * sizeof(TCHAR));
// First check for a "ProfileName" key
lStatus = RegQueryValueEx(hkeyUser, TEXT("ProfileName"), NULL, &dwType,
(LPBYTE)lpProfilePath, &cbBytes);
if (lStatus == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
{
// We're good to go.
LocalFree(pUser);
LocalFree(pTextSid);
RegCloseKey(hkeyProfileList);
RegCloseKey(hkeyUser);
return TRUE;
}
else
{
// Otherwise, grab the "ProfilePath" and get the last part of the name
cbBytes = (cchProfSize * sizeof(TCHAR));
lStatus = RegQueryValueEx(hkeyUser,TEXT("ProfileImagePath"), NULL, &dwType,
(LPBYTE)lpProfilePath, &cbBytes);
if (lStatus == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
{
// Return just the directory name portion of the profile path
//lstrcpyn(lpBuff, PathFindFileName(lpProfilePath), iSize);
LocalFree(pUser);
LocalFree(pTextSid);
RegCloseKey(hkeyProfileList);
RegCloseKey(hkeyUser);
return TRUE;
}
else
{
// Have exhausted our resources -- can't get the
// profile path.
LocalFree(pUser);
LocalFree(pTextSid);
RegCloseKey(hkeyProfileList);
RegCloseKey(hkeyUser);
return FALSE;
}
}
}
else
{
// Couldn't open reg key so we're hosed
LocalFree(pUser);
LocalFree(pTextSid);
RegCloseKey(hkeyProfileList);
return FALSE;
}
}
LocalFree(pUser);
LocalFree(pTextSid);
}
else
{
// For some completely unknown reason we have a NULL Sid string
// so we're doomed.
LocalFree(pTextSid);
return FALSE;
}
// We should never fall through to this point but if we do...
return FALSE;
}
//+--------------------------------------------------------------------------
//
// Function: GetTextualSid()
//
// Synopsis: WINNT only -- converts a SID to text.
//
// Returns: TRUE if successful, FALSE if not.
// Sets LastError on failure.
//
// Taken from the January 1998 MSDN reference.
//
//---------------------------------------------------------------------------
BOOL GetTextualSid( PSID pSid, // binary Sid
LPTSTR TextualSid, // buffer for Textual representation of Sid
LPDWORD lpdwBufferLen) // required/provided TextualSid buffersize
{
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwSidRev=SID_REVISION;
DWORD dwCounter;
DWORD dwSidSize;
// Validate the binary SID.
if(!IsValidSid(pSid))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// Get the identifier authority value from the SID.
psia = GetSidIdentifierAuthority(pSid);
// Get the number of subauthorities in the SID.
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
// Compute the buffer length.
// S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
// Check input buffer length.
// If too small, indicate the proper size and set last error.
if (*lpdwBufferLen < dwSidSize)
{
*lpdwBufferLen = dwSidSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
// Add 'S' prefix and revision number to the string.
dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
// Add SID identifier authority to the string.
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
}
else
{
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
TEXT("%lu"),
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
}
// Add SID subauthorities to the string.
//
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
{
dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
*GetSidSubAuthority(pSid, dwCounter) );
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return TRUE;
}
extern "C" VOID BuildNTJobName(LPTSTR lpJobName)
{
TCHAR szUser[MAX_PATH];
TCHAR szDomain[MAX_PATH];
TCHAR szProfile[MAX_PATH];
LPTSTR Current;
LPTSTR Dot;
if (!lpJobName) return; // Null pointers not allowed.
if (!GetCurrentUser(szUser, ARRAYSIZE(szUser),
szDomain, ARRAYSIZE(szDomain),
szProfile, ARRAYSIZE(szProfile)))
{
// GetCurrentUser failed so bail out.
return;
}
// Walk to the end of the lpJobName string
Dot = lpJobName;
while (*Dot) Dot = CharNext(Dot);
// Dot now points to the end of the lpJobName string. Backup until
// we get to the "dot" in the extension.
Dot = CharPrev(lpJobName, Dot);
while ((Dot > lpJobName) && (*Dot != TEXT('.'))) Dot = CharPrev(lpJobName, Dot);
// Ok truncate the extension by putting a NULL on the "dot".
*Dot = TEXT('\0');
// Walk to the end of the szProfile string
Current = szProfile;
while (*Current) Current = CharNext(Current);
// Current now points to the end of szProfile. Backup until we get
// to the first "\".
Current = CharPrev(szProfile, Current);
while ((Current > szProfile) && (*Current != TEXT('\\'))) Current = CharPrev(szProfile, Current);
*Current = TEXT('(');
lstrcat(lpJobName, TEXT(" "));
lstrcat(lpJobName, Current);
lstrcat(lpJobName, TEXT(").JOB"));
}
extern "C" BOOL IsUserAdmin(VOID)
/*++
Routine Description:
This routine returns TRUE if the caller's process is a
member of the Administrators local group.
Caller is NOT expected to be impersonating anyone and IS
expected to be able to open their own process and process
token.
Arguments:
None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
--*/
{
HANDLE Token;
DWORD BytesRequired;
PTOKEN_GROUPS Groups;
BOOL b;
DWORD i;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
//
// On non-NT platforms the user is administrator.
//
if(!IsPlatformNT()) {
return(TRUE);
}
//
// Open the process token.
//
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
return(FALSE);
}
b = FALSE;
Groups = NULL;
//
// Get group information.
//
if (!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
&& (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
&& GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired))
{
b = AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup
);
if (b) {
//
// See if the user has the administrator group.
//
b = FALSE;
for(i=0; i<Groups->GroupCount; i++) {
if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
b = TRUE;
break;
}
}
FreeSid(AdministratorsGroup);
}
}
//
// Clean up and return.
//
if(Groups) {
LocalFree((HLOCAL)Groups);
}
CloseHandle(Token);
return(b);
}