1626 lines
46 KiB
C++
1626 lines
46 KiB
C++
|
// 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);
|
||
|
}
|
||
|
|