Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1625 lines
46 KiB

  1. // File: schedule.cpp
  2. //
  3. // Contents: Functions needed to start, query, add, remove tasks
  4. // in Task Scheduler
  5. //
  6. // Microsoft Desktop Themes for Windows
  7. // Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
  8. #include <wchar.h>
  9. #include <windows.h>
  10. #include <mbctype.h>
  11. #include <objbase.h>
  12. #include <initguid.h>
  13. #include <mstask.h>
  14. #include <msterr.h>
  15. #include "frost.h"
  16. #define MSG_BOX_TSERR(hw,msg) MessageBox(hw, msg, szThemeName,\
  17. MB_OK | MB_ICONERROR | MB_APPLMODAL)
  18. #define SCHED_CLASS TEXT("SAGEWINDOWCLASS")
  19. #define SCHED_TITLE TEXT("SYSTEM AGENT COM WINDOW")
  20. #define SCHED_SERVICE_APP_NAME TEXT("mstask.exe")
  21. #define SCHED_SERVICE_NAME TEXT("Schedule")
  22. #define EVERY_MONTH (TASK_JANUARY | TASK_FEBRUARY | TASK_MARCH | TASK_APRIL |\
  23. TASK_MAY | TASK_JUNE | TASK_JULY | TASK_AUGUST |\
  24. TASK_SEPTEMBER | TASK_OCTOBER | TASK_NOVEMBER |\
  25. TASK_DECEMBER)
  26. //+--------------------------------------------------------------------------
  27. // Global variables defined in GLOBAL.H for compat. with C sources
  28. //---------------------------------------------------------------------------
  29. extern "C" HWND hWndApp = NULL;
  30. extern "C" HINSTANCE hInstApp = NULL;
  31. //+--------------------------------------------------------------------------
  32. // Global variables for use in SCHEDULE.CPP only
  33. //---------------------------------------------------------------------------
  34. ITaskScheduler *g_pITaskScheduler = NULL;
  35. TCHAR szRunServices[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices");
  36. TCHAR szScheduler[] = TEXT("SchedulingAgent");
  37. TCHAR szMSTask[] = TEXT("mstask.exe");
  38. TCHAR szUserName[MAX_PATH];
  39. TCHAR szPassword[MAX_PATH];
  40. //+--------------------------------------------------------------------------
  41. // Function Prototypes
  42. //---------------------------------------------------------------------------
  43. HRESULT Init(void);
  44. void Cleanup(void);
  45. extern "C" BOOL IsTaskSchedulerRunning();
  46. extern "C" BOOL StartTaskScheduler(BOOL);
  47. extern "C" BOOL IsThemesScheduled();
  48. extern "C" BOOL AddThemesTask(LPTSTR, BOOL);
  49. extern "C" BOOL DeleteThemesTask();
  50. extern "C" BOOL HandDeleteThemesTask();
  51. extern "C" BOOL IsPlatformNT();
  52. extern "C" BOOL GetCurrentUser(LPTSTR, DWORD, LPTSTR, DWORD, LPTSTR, DWORD);
  53. extern "C" BOOL GetTextualSid(PSID, LPTSTR, LPDWORD);
  54. extern "C" VOID BuildNTJobName(LPTSTR);
  55. extern "C" BOOL IsUserAdmin();
  56. //+--------------------------------------------------------------------------
  57. //
  58. // Function: PasswordDlgProc()
  59. //
  60. // Synopsis: WINNT only -- prompts user for name and password.
  61. //
  62. // Arguments: none (void)
  63. //
  64. //---------------------------------------------------------------------------
  65. INT_PTR CALLBACK PasswordDlgProc(HWND hDlg,
  66. UINT uMsg,
  67. WPARAM wParam,
  68. LPARAM lParam)
  69. {
  70. TCHAR szPWConfirm[MAX_PATH];
  71. TCHAR szErrMsg[MAX_PATH];
  72. TCHAR szThemeName[MAX_STRLEN]; // Used for msgbox title
  73. DWORD dwSize = 0;
  74. TCHAR szProfile[MAX_PATH];
  75. switch(uMsg)
  76. {
  77. case WM_INITDIALOG:
  78. if (GetCurrentUser(szPassword, /* Actually user name */
  79. ARRAYSIZE(szPassword),
  80. szUserName, /* Actually domain name */
  81. ARRAYSIZE(szUserName),
  82. szProfile,
  83. ARRAYSIZE(szProfile)))
  84. {
  85. // GetCurrentUser succeeded so build the domain\user
  86. //
  87. // Remember these variable names are bogus --
  88. // szUserName is actually the domain name
  89. // szPassword is actually the user name
  90. //
  91. if (szPassword[0]) lstrcat(szUserName, TEXT("\\"));
  92. lstrcat(szUserName, szPassword);
  93. }
  94. else
  95. {
  96. // GetCurrentUser failed so do this as last resort
  97. dwSize = ARRAYSIZE(szUserName);
  98. GetUserName(szUserName, &dwSize);
  99. }
  100. *szPassword = 0;
  101. SetDlgItemText(hDlg, EDIT_USER, szUserName);
  102. SetFocus(GetDlgItem(hDlg, EDIT_PW));
  103. return FALSE; // Return false to keep focus on PW control
  104. break;
  105. case WM_COMMAND:
  106. switch (wParam)
  107. {
  108. case IDOK:
  109. GetDlgItemText(hDlg, EDIT_USER, szUserName, MAX_PATH);
  110. GetDlgItemText(hDlg, EDIT_PW, szPassword, MAX_PATH);
  111. GetDlgItemText(hDlg, EDIT_PWCONFIRM, szPWConfirm, MAX_PATH);
  112. if (lstrcmp(szPassword, szPWConfirm))
  113. {
  114. // PW and PWCONFIRM don't match
  115. LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
  116. LoadString(hInstApp, STR_PW_NOMATCH, szErrMsg, MAX_PATH);
  117. MessageBox(hWndApp, szErrMsg, szThemeName,
  118. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  119. SetDlgItemText(hDlg, EDIT_PW, TEXT("\0"));
  120. SetDlgItemText(hDlg, EDIT_PWCONFIRM, TEXT("\0"));
  121. SetActiveWindow(GetDlgItem(hDlg, EDIT_PW));
  122. SetFocus(GetDlgItem(hDlg, EDIT_PW));
  123. break;
  124. }
  125. else
  126. {
  127. EndDialog(hDlg,1);
  128. break;
  129. }
  130. case IDCANCEL:
  131. szUserName[0] = TEXT('\0');
  132. szPassword[0] = TEXT('\0');
  133. EndDialog(hDlg, 0);
  134. break;
  135. }
  136. break;
  137. default:
  138. return FALSE;
  139. } // switch uMsg
  140. return TRUE;
  141. } // PasswordDlgProc
  142. //+--------------------------------------------------------------------------
  143. //
  144. // Function: IsPlatformNT()
  145. //
  146. // Synopsis: Checks to see if the os is NT or not.
  147. //
  148. // Arguments: none (void)
  149. //
  150. // Returns: TRUE if NT, FALSE if not.
  151. //
  152. //---------------------------------------------------------------------------
  153. extern "C" BOOL IsPlatformNT()
  154. {
  155. OSVERSIONINFO osver;
  156. osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  157. // Determine what version of OS we are running on.
  158. GetVersionEx(&osver);
  159. if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
  160. return TRUE;
  161. else
  162. return FALSE;
  163. }
  164. //+--------------------------------------------------------------------------
  165. //
  166. // Function: IsTaskSchedulerRunning()
  167. //
  168. // Synopsis: Looks for TS window to determince TS is running.
  169. //
  170. // Arguments: none (void)
  171. //
  172. // Returns: TRUE if running, FALSE if not.
  173. //
  174. //---------------------------------------------------------------------------
  175. extern "C" BOOL IsTaskSchedulerRunning()
  176. {
  177. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  178. if (hwnd == NULL)
  179. {
  180. //MessageBox(hWndApp, TEXT("TS is not running"), TEXT("Desktop Themes"), MB_OK | MB_APPLMODAL);
  181. return FALSE;
  182. }
  183. else
  184. {
  185. //MessageBox(hWndApp, TEXT("TS is running"), TEXT("Desktop Themes"), MB_OK | MB_APPLMODAL);
  186. return TRUE;
  187. }
  188. }
  189. //---------------------------------------------------------------------------
  190. // Function: StartTaskScheduler
  191. // Synopsis: Start the task scheduler service if it isn't already running.
  192. // Arguments: bPrompt -- TRUE == prompt user before starting.
  193. // FALSE == just start it, don't prompt user.
  194. // Returns: TRUE if successful, FALSE if not.
  195. // Notes: This function works in Win9x only.
  196. // If the service is running but paused, does nothing.
  197. //---------------------------------------------------------------------------
  198. extern "C" BOOL StartTaskScheduler(BOOL bPrompt)
  199. {
  200. STARTUPINFO sui;
  201. PROCESS_INFORMATION pi;
  202. TCHAR szApp[MAX_PATH];
  203. LPTSTR pszPath;
  204. DWORD dwRet;
  205. BOOL fRet;
  206. TCHAR szErrMsg[MAX_PATH];
  207. TCHAR szThemeName[MAX_STRLEN]; // Used for msgbox title
  208. int MBChoice; // User's reply to Yes/No dialog
  209. DWORD dwDisposition;
  210. HKEY hKey;
  211. LONG lret;
  212. LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
  213. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  214. if (hwnd != NULL) {
  215. // It is already running.
  216. return TRUE;
  217. }
  218. // If specified, prompt user before attempting to start
  219. // Task Scheduler.
  220. if (bPrompt) {
  221. LoadString(hInstApp, STR_ERRTSNOTRUN, szErrMsg, MAX_PATH);
  222. MBChoice = MessageBox(hWndApp, szErrMsg, szThemeName,
  223. MB_YESNO | MB_ICONQUESTION | MB_APPLMODAL);
  224. // Did user opt to NOT start task scheduler?
  225. if (IDYES != MBChoice) return FALSE;
  226. }
  227. if (!IsPlatformNT()) {
  228. // Start the Win9x version of TaskScheduler.
  229. // Execute the task scheduler process.
  230. ZeroMemory(&sui, sizeof(sui));
  231. sui.cb = sizeof(STARTUPINFO);
  232. dwRet = SearchPath(NULL,
  233. SCHED_SERVICE_APP_NAME,
  234. NULL,
  235. MAX_PATH,
  236. szApp,
  237. &pszPath);
  238. if (dwRet == 0) {
  239. LoadString(hInstApp, STR_ERRTSNOTFOUND, szErrMsg, MAX_PATH);
  240. MessageBox(hWndApp, szErrMsg, szThemeName,
  241. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  242. return FALSE;
  243. }
  244. fRet = CreateProcess(szApp,
  245. NULL,
  246. NULL,
  247. NULL,
  248. FALSE,
  249. CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  250. NULL,
  251. NULL,
  252. &sui,
  253. &pi);
  254. if (fRet == 0) {
  255. LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
  256. MessageBox(hWndApp, szErrMsg, szThemeName,
  257. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  258. return FALSE;
  259. }
  260. CloseHandle(pi.hProcess);
  261. CloseHandle(pi.hThread);
  262. // Assume that MSTASK.EXE was successfully started. We need to
  263. // add mstask.exe to the RunServices branch of the registry.
  264. hKey = NULL;
  265. lret = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  266. szRunServices,
  267. 0,
  268. NULL,
  269. REG_OPTION_NON_VOLATILE,
  270. KEY_WRITE,
  271. NULL,
  272. &hKey,
  273. &dwDisposition);
  274. if (lret == ERROR_SUCCESS) {
  275. // RegDeleteValue(hKey, szScheduler);
  276. lret = RegSetValueEx(hKey,
  277. szScheduler,
  278. 0,
  279. REG_SZ,
  280. (CONST BYTE *)szMSTask,
  281. SZSIZEINBYTES(szMSTask));
  282. }
  283. if (hKey) RegCloseKey(hKey);
  284. return TRUE;
  285. }
  286. else
  287. {
  288. // If not Win9x then start the NT version as a TaskScheduler service.
  289. SC_HANDLE hSC = NULL;
  290. SC_HANDLE hSchSvc = NULL;
  291. // Does the user have administrative privileges? If not, the
  292. // user can't start TS.
  293. if (!IsUserAdmin())
  294. {
  295. LoadString(hInstApp, STR_ERRTSNOTADMIN, szErrMsg, MAX_PATH);
  296. MessageBox(hWndApp, szErrMsg, szThemeName,
  297. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  298. return FALSE;
  299. }
  300. hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  301. if (hSC == NULL)
  302. {
  303. return FALSE;
  304. // NEED TO ADD ERROR DIALOG HERE
  305. // return GetLastError();
  306. }
  307. hSchSvc = OpenService(hSC,
  308. SCHED_SERVICE_NAME,
  309. SERVICE_START | SERVICE_QUERY_STATUS);
  310. CloseServiceHandle(hSC);
  311. if (hSchSvc == NULL)
  312. {
  313. LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
  314. MessageBox(hWndApp, szErrMsg, szThemeName,
  315. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  316. return FALSE;
  317. }
  318. SERVICE_STATUS SvcStatus;
  319. if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
  320. {
  321. CloseServiceHandle(hSchSvc);
  322. LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
  323. MessageBox(hWndApp, szErrMsg, szThemeName,
  324. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  325. return FALSE;
  326. }
  327. if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
  328. {
  329. // The service is already running.
  330. CloseServiceHandle(hSchSvc);
  331. return TRUE;
  332. }
  333. if (StartService(hSchSvc, 0, NULL) == FALSE)
  334. {
  335. CloseServiceHandle(hSchSvc);
  336. LoadString(hInstApp, STR_ERRTSNOSTART, szErrMsg, MAX_PATH);
  337. MessageBox(hWndApp, szErrMsg, szThemeName,
  338. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  339. return FALSE;
  340. }
  341. CloseServiceHandle(hSchSvc);
  342. return TRUE;
  343. }
  344. } // END StartTaskScheduler()
  345. //+--------------------------------------------------------------------------
  346. //
  347. // Function: Init()
  348. //
  349. // Synopsis: Called to initialize and instantiate a task
  350. // scheduler object.
  351. //
  352. // Arguments: none (void)
  353. //
  354. // Returns: HRESULT indicating success or failure. S_OK on success.
  355. //
  356. // Side effect: Sets global pointer g_pITaskScheduler, for use in other
  357. // functions.
  358. //
  359. //---------------------------------------------------------------------------
  360. HRESULT Init()
  361. {
  362. HRESULT hr = S_OK;
  363. // Bring in the library
  364. hr = CoInitialize(NULL);
  365. if (FAILED(hr))
  366. {
  367. return hr;
  368. }
  369. // Create the pointer to Task Scheduler object
  370. // CLSID from the header file mstask.h
  371. hr = CoCreateInstance(
  372. CLSID_CTaskScheduler,
  373. NULL,
  374. CLSCTX_INPROC_SERVER,
  375. IID_ITaskScheduler,
  376. (void **) &g_pITaskScheduler);
  377. // Should we fail, unload the library
  378. if (FAILED(hr))
  379. {
  380. CoUninitialize();
  381. }
  382. return hr;
  383. }
  384. //+--------------------------------------------------------------------------
  385. //
  386. // Function: Cleanup()
  387. //
  388. // Synopsis: Called to clean up OLE, memory, etc. before termination
  389. //
  390. // Arguments: none (void)
  391. //
  392. // Returns: nothing (void)
  393. //
  394. // Side effect: Cancels the global pointer g_pITaskScheduler.
  395. //
  396. //---------------------------------------------------------------------------
  397. void Cleanup()
  398. {
  399. if (g_pITaskScheduler)
  400. {
  401. g_pITaskScheduler->Release();
  402. g_pITaskScheduler = NULL;
  403. }
  404. // Unload the library, now that our pointer is freed.
  405. CoUninitialize();
  406. return;
  407. }
  408. //+--------------------------------------------------------------------------
  409. //
  410. // Function: IsThemesScheduled()
  411. //
  412. // Synopsis: Enumerates tasks and returns TRUE if Themes.job exists.
  413. // Returns FALSE if it does not.
  414. //
  415. // Arguments: none (void). Requires g_pITaskScheduler.
  416. //
  417. // Returns: TRUE if Themes.job exists, else FALSE
  418. //
  419. //---------------------------------------------------------------------------
  420. extern "C" BOOL IsThemesScheduled()
  421. {
  422. HRESULT hr = S_OK, hrLoop = S_OK;
  423. IEnumWorkItems *pIEnumWorkItems;
  424. IUnknown *pIU;
  425. ITask *pITask;
  426. ULONG ulTasksToGet = 1, ulActualTasksRetrieved = 0;
  427. LPWSTR *rgpwszNames;
  428. TCHAR szDefaultJobName[MAX_PATH];
  429. BOOL bResult;
  430. UINT uCodePage;
  431. #ifndef UNICODE
  432. CHAR szJobNameA[MAX_PATH];
  433. #endif
  434. // For protection
  435. g_pITaskScheduler = NULL;
  436. // String conversion initialization
  437. uCodePage = _getmbcp();
  438. // Attempt to initialize OLE and fill in the global g_pITaskScheduler
  439. hr = Init();
  440. if (FAILED(hr))
  441. {
  442. return FALSE;
  443. }
  444. // Get the default name for a Themes task
  445. LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
  446. // If this is NT we need to append the user profile name onto the
  447. // end of this task.
  448. if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
  449. //
  450. // Get an enumeration pointer, using ITaskScheduler::Enum
  451. //
  452. hr = g_pITaskScheduler->Enum(&pIEnumWorkItems);
  453. if (FAILED(hr))
  454. {
  455. // LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  456. // MSG_BOX_TSERR(hWndApp, szErrMsg);
  457. Cleanup();
  458. return FALSE;
  459. }
  460. bResult = FALSE;
  461. do
  462. {
  463. // Get a single work item, using IEnumWorkItems::Next
  464. hrLoop = pIEnumWorkItems->Next(ulTasksToGet, &rgpwszNames,
  465. &ulActualTasksRetrieved);
  466. if (hrLoop == S_FALSE)
  467. {
  468. // There are no more waiting tasks to look at
  469. break;
  470. }
  471. // Attach to the work item, using ITaskScheduler::Activate
  472. hr = g_pITaskScheduler->Activate(rgpwszNames[0], IID_ITask, &pIU);
  473. if (FAILED(hr))
  474. {
  475. // LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  476. // MSG_BOX_TSERR(hWndApp, szErrMsg);
  477. bResult = FALSE;
  478. break;
  479. }
  480. // QI pIU for pITask
  481. hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
  482. pIU->Release();
  483. pIU = NULL;
  484. if (FAILED(hr))
  485. {
  486. // LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  487. // MSG_BOX_TSERR(hWndApp, szErrMsg);
  488. bResult = FALSE;
  489. break;
  490. }
  491. // Compare task name
  492. #ifndef UNICODE
  493. // No UNICODE so we need to convert the wide string returned
  494. // by ITask into an ANSI string.
  495. WideCharToMultiByte(uCodePage, 0, rgpwszNames[0], -1,
  496. szJobNameA, MAX_PATH, NULL, NULL);
  497. // MessageBox(hWndApp, szJobNameA, szThemeName,
  498. // MB_OK | MB_APPLMODAL);
  499. if (!lstrcmp(szJobNameA, szDefaultJobName)) bResult = TRUE;
  500. #else
  501. // We're living in a UNICODE world so no need to convert
  502. // the string from ITask.
  503. // MessageBox(hWndApp, rgpwszNames[0], szThemeName,
  504. // MB_OK | MB_APPLMODAL);
  505. if (!lstrcmp(rgpwszNames[0], szDefaultJobName)) bResult = TRUE;
  506. #endif
  507. // Clean up each element in the array of job names, then
  508. // clean up the final array.
  509. CoTaskMemFree(rgpwszNames[0]);
  510. CoTaskMemFree(rgpwszNames);
  511. // Free the ITask pointer
  512. pITask->Release();
  513. } while(!bResult);
  514. // Release the enumeration pointer
  515. pITask = NULL;
  516. pIEnumWorkItems->Release();
  517. pIEnumWorkItems = NULL;
  518. Cleanup();
  519. return bResult; //
  520. }
  521. //+--------------------------------------------------------------------------
  522. //
  523. // Function: DeleteThemesTask()
  524. //
  525. // Synopsis: Deletes Themes task from Task Scheduler.
  526. //
  527. // Returns: TRUE if OK, FALSE if FAIL.
  528. //
  529. //---------------------------------------------------------------------------
  530. extern "C" BOOL DeleteThemesTask()
  531. {
  532. HRESULT hr = S_OK;
  533. UINT uCodePage;
  534. TCHAR szDefaultJobName[MAX_PATH];
  535. #ifndef UNICODE
  536. WCHAR szJobNameW[MAX_PATH];
  537. #endif
  538. // String conversion initialization
  539. uCodePage = _getmbcp();
  540. // For protection
  541. g_pITaskScheduler = NULL;
  542. // Attempt to initialize OLE and fill in the global g_pITaskScheduler
  543. hr = Init();
  544. if (FAILED(hr))
  545. {
  546. // LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  547. // MSG_BOX_TSERR(hWndApp, szErrMsg);
  548. return FALSE;
  549. }
  550. // Get the default name for a Themes task
  551. LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
  552. // If this is NT we need to append the user profile name onto the
  553. // end of this task.
  554. if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
  555. #ifndef UNICODE
  556. // No UNICODE so convert the string to WCHAR format to
  557. // please the TS interface
  558. MultiByteToWideChar(uCodePage, 0, szDefaultJobName, -1,
  559. szJobNameW, MAX_PATH);
  560. // Delete it
  561. hr = g_pITaskScheduler->Delete(szJobNameW);
  562. #else // UNICODE
  563. // We're UNICODE so we don't need to convert the string before
  564. // calling TS
  565. hr = g_pITaskScheduler->Delete(szDefaultJobName);
  566. #endif
  567. Cleanup();
  568. return TRUE; // Returns TRUE regardless of hr value.
  569. }
  570. //+--------------------------------------------------------------------------
  571. //
  572. // Function: AddThemesTask()
  573. //
  574. // Synopsis: Adds a new work item to the Scheduled Tasks folder.
  575. //
  576. // Arguments: lpwszThemesExe - fully qualified path to Themes.exe.
  577. // bShowErrors - if TRUE, ATT shows error dialogs else
  578. // it fails silently.
  579. //
  580. // Returns: TRUE if successful, FALSE if not.
  581. //
  582. //---------------------------------------------------------------------------
  583. extern "C" BOOL AddThemesTask(LPTSTR lpszThemesExe, BOOL bShowErrors)
  584. {
  585. HRESULT hr = S_OK;
  586. IUnknown *pIU;
  587. IPersistFile *pIPF;
  588. ITask *pITask;
  589. ITaskTrigger *pITaskTrig;
  590. DWORD dwTaskFlags, dwTrigFlags;
  591. WORD wTrigNumber;
  592. TASK_TRIGGER TaskTrig;
  593. UINT uCodePage;
  594. //TCHAR szUserName[MAX_PATH];
  595. //TCHAR szPassword[MAX_PATH];
  596. WCHAR szRotateCommandW[] = L"/r";
  597. TCHAR szDefaultJobName[MAX_PATH];
  598. TCHAR szJobComment[MAX_PATH];
  599. #ifndef UNICODE
  600. WCHAR szUserNameW[MAX_PATH];
  601. WCHAR szPasswordW[MAX_PATH];
  602. WCHAR szThemesExeW[MAX_PATH];
  603. WCHAR szJobNameW[MAX_PATH];
  604. WCHAR szJobCommentW[MAX_PATH];
  605. #endif
  606. SYSTEMTIME LocalTime;
  607. TCHAR szErrMsg[MAX_PATH];
  608. TCHAR szThemeName[MAX_STRLEN]; // msg box title
  609. HKEY hKey;
  610. DWORD dwDisposition;
  611. LONG lret;
  612. INT_PTR iResult;
  613. LoadString(hInstApp, STR_APPNAME, szThemeName, MAX_STRLEN);
  614. LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
  615. LoadString(hInstApp, STR_JOB_COMMENT, szJobComment, MAX_PATH);
  616. // If this is NT we need to append the user profile name onto the
  617. // end of this task.
  618. if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
  619. // String conversion initialization
  620. uCodePage = _getmbcp();
  621. // For protection
  622. g_pITaskScheduler = NULL;
  623. // Attempt to initialize OLE and fill in the global g_pITaskScheduler
  624. hr = Init();
  625. if (FAILED(hr))
  626. {
  627. if (bShowErrors) {
  628. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  629. MSG_BOX_TSERR(hWndApp, szErrMsg);
  630. }
  631. return FALSE;
  632. }
  633. // Add the task. Most likely failure is that work item already exists.
  634. // Uses ITaskScheduler::NewWorkItem
  635. #ifndef UNICODE
  636. // No UNICODE so convert string to wide before adding task
  637. MultiByteToWideChar(uCodePage, 0, szDefaultJobName, -1,
  638. szJobNameW, MAX_PATH);
  639. hr = g_pITaskScheduler->NewWorkItem(szJobNameW,
  640. CLSID_CTask,
  641. IID_ITask,
  642. &pIU);
  643. #else
  644. // UNICODE, so no need to convert string to WIDE before adding task
  645. hr = g_pITaskScheduler->NewWorkItem(szDefaultJobName,
  646. CLSID_CTask,
  647. IID_ITask,
  648. &pIU);
  649. #endif
  650. if (FAILED(hr))
  651. {
  652. if (bShowErrors) {
  653. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  654. MSG_BOX_TSERR(hWndApp, szErrMsg);
  655. }
  656. Cleanup();
  657. return FALSE;
  658. }
  659. // We now have an IUnknown pointer. This is queried for an ITask
  660. // pointer on the work item we just added.
  661. hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
  662. if (FAILED(hr))
  663. {
  664. if (bShowErrors) {
  665. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  666. MSG_BOX_TSERR(hWndApp, szErrMsg);
  667. }
  668. pIU->Release();
  669. Cleanup();
  670. return FALSE;
  671. }
  672. // Cleanup pIUnknown, as we are done with it.
  673. pIU->Release();
  674. pIU = NULL;
  675. //
  676. // If this is for NT we need to get and set the user account
  677. // information. ITask::SetAccountInformation
  678. //
  679. if (IsPlatformNT())
  680. {
  681. szUserName[0] = TEXT('\0'); // global user name string
  682. szPassword[0] = TEXT('\0'); // global password string
  683. // Prompt for the user name and password
  684. //
  685. // Password dialog returns:
  686. // -1 if DialogBox() fails
  687. // 0 if user cancels
  688. // 1 if PW entered OK
  689. iResult = 0;
  690. iResult = DialogBox(hInstApp,
  691. MAKEINTRESOURCE(DLG_PASSWORD),
  692. hWndApp,
  693. PasswordDlgProc);
  694. if (iResult < 1)
  695. {
  696. // Either the password dialog failed or the user Canceled
  697. // it so bail out.
  698. pITask->Release();
  699. Cleanup();
  700. return FALSE;
  701. }
  702. #ifndef UNICODE
  703. // No UNICODE so we need to convert from ANSI to WCHAR before
  704. // calling SetAccountInformation
  705. MultiByteToWideChar(uCodePage, 0, szUserName, -1,
  706. szUserNameW, MAX_PATH);
  707. MultiByteToWideChar(uCodePage, 0, szPassword, -1,
  708. szPasswordW, MAX_PATH);
  709. hr = pITask->SetAccountInformation(szUserNameW, szPasswordW);
  710. #else
  711. // UNICODE so no need to convert strings
  712. hr = pITask->SetAccountInformation(szUserName, szPassword);
  713. #endif // UNICODE
  714. if (FAILED(hr))
  715. {
  716. if (bShowErrors) {
  717. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  718. MSG_BOX_TSERR(hWndApp, szErrMsg);
  719. }
  720. pITask->Release();
  721. Cleanup();
  722. return FALSE;
  723. }
  724. } // IsPlatformNT
  725. // Set command name with ITask::SetApplicationName
  726. #ifndef UNICODE
  727. // No UNICODE so need to convert string to WIDE
  728. MultiByteToWideChar(uCodePage, 0, lpszThemesExe, -1,
  729. szThemesExeW, MAX_PATH);
  730. hr = pITask->SetApplicationName(szThemesExeW);
  731. #else
  732. // UNICODE so no need to convert string
  733. hr = pITask->SetApplicationName(lpszThemesExe);
  734. #endif
  735. if (FAILED(hr))
  736. {
  737. if (bShowErrors) {
  738. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  739. MSG_BOX_TSERR(hWndApp, szErrMsg);
  740. }
  741. pITask->Release();
  742. Cleanup();
  743. return FALSE;
  744. }
  745. // Set task parameters with ITask::SetParameters
  746. hr = pITask->SetParameters(szRotateCommandW);
  747. if (FAILED(hr))
  748. {
  749. if (bShowErrors) {
  750. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  751. MSG_BOX_TSERR(hWndApp, szErrMsg);
  752. }
  753. pITask->Release();
  754. Cleanup();
  755. return FALSE;
  756. }
  757. // Set the comment, so we know how this job got there
  758. // Uses ITask::SetComment
  759. #ifndef UNICODE
  760. // No UNICODE so convert to WIDE
  761. MultiByteToWideChar(uCodePage, 0, szJobComment, -1,
  762. szJobCommentW, MAX_PATH);
  763. hr = pITask->SetComment(szJobCommentW);
  764. #else
  765. // UNICODE so no need to convert string
  766. hr = pITask->SetComment(szJobComment);
  767. #endif
  768. if (FAILED(hr))
  769. {
  770. if (bShowErrors) {
  771. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  772. MSG_BOX_TSERR(hWndApp, szErrMsg);
  773. }
  774. pITask->Release();
  775. Cleanup();
  776. return FALSE;
  777. }
  778. // Set the flags on the task object
  779. // Use ITask::SetFlags
  780. dwTaskFlags = NULL;
  781. hr = pITask->SetFlags(dwTaskFlags);
  782. if (FAILED(hr))
  783. {
  784. if (bShowErrors) {
  785. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  786. MSG_BOX_TSERR(hWndApp, szErrMsg);
  787. }
  788. pITask->Release();
  789. Cleanup();
  790. return FALSE;
  791. }
  792. // Now, create a trigger to run the task at our specified time.
  793. // Uses ITask::CreateTrigger()
  794. hr = pITask->CreateTrigger(&wTrigNumber, &pITaskTrig);
  795. if (FAILED(hr))
  796. {
  797. if (bShowErrors) {
  798. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  799. MSG_BOX_TSERR(hWndApp, szErrMsg);
  800. }
  801. pITask->Release();
  802. Cleanup();
  803. return FALSE;
  804. }
  805. // Now, fill in the trigger as necessary.
  806. GetLocalTime(&LocalTime);
  807. if (12 == LocalTime.wMonth) {
  808. LocalTime.wMonth = 1;
  809. LocalTime.wYear++;
  810. }
  811. else LocalTime.wMonth++;
  812. dwTrigFlags = 0;
  813. TaskTrig.cbTriggerSize = sizeof(TASK_TRIGGER);
  814. TaskTrig.Reserved1 = 0;
  815. TaskTrig.wBeginYear = LocalTime.wYear;
  816. TaskTrig.wBeginMonth = LocalTime.wMonth;
  817. TaskTrig.wBeginDay = 1;
  818. TaskTrig.wEndYear = 0;
  819. TaskTrig.wEndMonth = 0;
  820. TaskTrig.wEndDay = 0;
  821. TaskTrig.wStartHour = 14;
  822. TaskTrig.wStartMinute = 0;
  823. TaskTrig.MinutesDuration = 0;
  824. TaskTrig.MinutesInterval = 0;
  825. TaskTrig.rgFlags = dwTrigFlags;
  826. TaskTrig.TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE;
  827. TaskTrig.Type.MonthlyDate.rgfDays = 1;
  828. TaskTrig.Type.MonthlyDate.rgfMonths = EVERY_MONTH;
  829. TaskTrig.wRandomMinutesInterval = 0;
  830. TaskTrig.Reserved2 = 0;
  831. // Add this trigger to the task using ITaskTrigger::SetTrigger
  832. hr = pITaskTrig->SetTrigger(&TaskTrig);
  833. if (FAILED(hr))
  834. {
  835. if (bShowErrors) {
  836. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  837. MSG_BOX_TSERR(hWndApp, szErrMsg);
  838. }
  839. pITaskTrig->Release();
  840. pITask->Release();
  841. Cleanup();
  842. return FALSE;
  843. }
  844. // Make the changes permanent
  845. // Requires using IPersistFile::Save()
  846. hr = pITask->QueryInterface(IID_IPersistFile, (void **) &pIPF);
  847. if (FAILED(hr))
  848. {
  849. if (bShowErrors) {
  850. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  851. MSG_BOX_TSERR(hWndApp, szErrMsg);
  852. }
  853. pITaskTrig->Release();
  854. pITask->Release();
  855. Cleanup();
  856. return FALSE;
  857. }
  858. hr = pIPF->Save(NULL, FALSE);
  859. if (FAILED(hr))
  860. {
  861. if (bShowErrors) {
  862. LoadString(hInstApp, STR_ERRTS, szErrMsg, MAX_PATH);
  863. MSG_BOX_TSERR(hWndApp, szErrMsg);
  864. }
  865. pITaskTrig->Release();
  866. pITask->Release();
  867. pIPF->Release();
  868. Cleanup();
  869. return FALSE;
  870. }
  871. // We no longer need ITask
  872. pITask->Release();
  873. pITask = NULL;
  874. // Done with ITaskTrigger pointer
  875. pITaskTrig->Release();
  876. pITaskTrig = NULL;
  877. // Done with IPersistFile
  878. pIPF->Release();
  879. pIPF = NULL;
  880. Cleanup();
  881. // Finally -- we have successfully added the task but we need to
  882. // make sure that Task Scheduler is in the RunServices branch of
  883. // the registry so it will start every time.
  884. hKey = NULL;
  885. lret = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  886. szRunServices,
  887. 0,
  888. NULL,
  889. REG_OPTION_NON_VOLATILE,
  890. KEY_WRITE,
  891. NULL,
  892. &hKey,
  893. &dwDisposition);
  894. if (lret == ERROR_SUCCESS) {
  895. // RegDeleteValue(hKey, szScheduler);
  896. lret = RegSetValueEx(hKey,
  897. szScheduler,
  898. 0,
  899. REG_SZ,
  900. (CONST BYTE *)szMSTask,
  901. (SZSIZEINBYTES(szMSTask) + 1));
  902. }
  903. if (hKey) RegCloseKey(hKey);
  904. return TRUE;
  905. }
  906. extern "C" BOOL HandDeleteThemesTask()
  907. {
  908. TCHAR szJobFile[MAX_PATH]; // Full path to %windir%\Tasks\Themes.job
  909. TCHAR szDefaultJobName[MAX_PATH];
  910. if (!GetWindowsDirectory(szJobFile, MAX_PATH)) return FALSE;
  911. lstrcat(szJobFile, TEXT("\\Tasks\\\0"));
  912. LoadString(hInstApp, STR_JOB_NAME, szDefaultJobName, MAX_PATH);
  913. // If this is NT we need to append the user profile name onto the
  914. // end of this task.
  915. if (IsPlatformNT()) BuildNTJobName(szDefaultJobName);
  916. lstrcat(szJobFile, szDefaultJobName);
  917. DeleteFile(szJobFile);
  918. return TRUE;
  919. }
  920. //---------------------------------------------------------------------------
  921. // GetUserToken - Gets the current process's user token and returns
  922. // it. It can later be free'd with LocalFree.
  923. //---------------------------------------------------------------------------
  924. PTOKEN_USER GetUserToken(HANDLE hUser)
  925. {
  926. PTOKEN_USER pUser;
  927. DWORD dwSize = 64;
  928. HANDLE hToClose = NULL;
  929. if (hUser == NULL)
  930. {
  931. OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser);
  932. hToClose = hUser;
  933. }
  934. pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwSize);
  935. if (pUser)
  936. {
  937. DWORD dwNewSize;
  938. BOOL fOk = GetTokenInformation(hUser, TokenUser, pUser, dwSize, &dwNewSize);
  939. if (!fOk && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
  940. {
  941. LocalFree((HLOCAL)pUser);
  942. pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwNewSize);
  943. if (pUser)
  944. {
  945. fOk = GetTokenInformation( hUser, TokenUser, pUser, dwNewSize, &dwNewSize);
  946. }
  947. }
  948. if (!fOk)
  949. {
  950. LocalFree((HLOCAL)pUser);
  951. pUser = NULL;
  952. }
  953. }
  954. if (hToClose)
  955. CloseHandle(hToClose);
  956. return pUser;
  957. }
  958. //----------------------------------------------------------------------------
  959. // GetCurrentUser - Fills in a buffer with the unique name that we are using
  960. // for the currently logged on user. On NT, this name is
  961. // used for the name of the profile directory and for the
  962. // name of the per-user recycle bin directory on a security
  963. // aware drive.
  964. //
  965. // Parameters:
  966. // lpAccountName -- buffer to receive user account name
  967. // lpDomainName -- buffer to receive domain name
  968. // lpProfilePath -- receives fully qualified path to user's
  969. // profile directory. If the caller does
  970. // not want the profile path NULL may be
  971. // passed in for this parameter.
  972. //----------------------------------------------------------------------------
  973. extern "C" BOOL GetCurrentUser(LPTSTR lpAccountName, DWORD cchAcctSize,
  974. LPTSTR lpDomainName, DWORD cchDomSize,
  975. LPTSTR lpProfilePath, DWORD cchProfSize)
  976. {
  977. PTOKEN_USER pUser;
  978. LPTSTR pTextSid = 0;
  979. DWORD cbBytes;
  980. SID_NAME_USE SNU;
  981. HANDLE hUser;
  982. // Take the easy outs -- no NULL parms for first four.
  983. if (!lpAccountName || !lpDomainName || !&cchAcctSize || !&cchDomSize) return FALSE;
  984. // Initialize these strings to NULL.
  985. *lpAccountName = 0;
  986. *lpDomainName = 0;
  987. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser))
  988. {
  989. return FALSE;
  990. }
  991. pUser = GetUserToken(hUser);
  992. CloseHandle(hUser);
  993. if (!pUser)
  994. return FALSE;
  995. if (!IsValidSid(pUser->User.Sid))
  996. {
  997. LocalFree(pUser);
  998. return FALSE;
  999. }
  1000. if (!LookupAccountSid(NULL,
  1001. pUser->User.Sid,
  1002. lpAccountName,
  1003. &cchAcctSize,
  1004. lpDomainName,
  1005. &cchDomSize,
  1006. &SNU))
  1007. {
  1008. // LookupAccountSid failed
  1009. LocalFree(pUser);
  1010. return FALSE;
  1011. }
  1012. // Does the caller want the profile path?
  1013. if (!lpProfilePath)
  1014. {
  1015. // No, so cleanup and hit the road.
  1016. LocalFree(pUser);
  1017. return TRUE;
  1018. }
  1019. // Have the Account and Domain Name. Next we need to get
  1020. // a text based SID so we can lookup the profile path in
  1021. // the registry.
  1022. // First let's find out how big a buffer we need for the
  1023. // text Sid.
  1024. *lpProfilePath = 0;
  1025. cbBytes = 0;
  1026. if ((!GetTextualSid(pUser->User.Sid, pTextSid, &cbBytes)) &&
  1027. (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
  1028. {
  1029. pTextSid = (LPTSTR)LocalAlloc(LPTR, cbBytes);
  1030. if (!pTextSid)
  1031. {
  1032. LocalFree(pUser);
  1033. return FALSE;
  1034. }
  1035. if (!GetTextualSid(pUser->User.Sid, pTextSid, &cbBytes))
  1036. {
  1037. LocalFree(pUser);
  1038. return FALSE;
  1039. }
  1040. }
  1041. else
  1042. {
  1043. // Failed to get a text SID so we're outta here.
  1044. LocalFree((HLOCAL)pUser);
  1045. return FALSE;
  1046. }
  1047. // OK, now we should have a text-based SID. Used this to find
  1048. // the profilepath in the registry.
  1049. if (pTextSid)
  1050. {
  1051. HKEY hkeyProfileList;
  1052. // Open the registry and find the appropriate name
  1053. LONG lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"), 0,
  1054. KEY_READ, &hkeyProfileList);
  1055. if (lStatus == ERROR_SUCCESS)
  1056. {
  1057. HKEY hkeyUser;
  1058. lStatus = RegOpenKeyEx(hkeyProfileList, pTextSid, 0, KEY_READ, &hkeyUser);
  1059. if (lStatus == ERROR_SUCCESS)
  1060. {
  1061. DWORD dwType;
  1062. cbBytes = (cchProfSize * sizeof(TCHAR));
  1063. // First check for a "ProfileName" key
  1064. lStatus = RegQueryValueEx(hkeyUser, TEXT("ProfileName"), NULL, &dwType,
  1065. (LPBYTE)lpProfilePath, &cbBytes);
  1066. if (lStatus == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
  1067. {
  1068. // We're good to go.
  1069. LocalFree(pUser);
  1070. LocalFree(pTextSid);
  1071. RegCloseKey(hkeyProfileList);
  1072. RegCloseKey(hkeyUser);
  1073. return TRUE;
  1074. }
  1075. else
  1076. {
  1077. // Otherwise, grab the "ProfilePath" and get the last part of the name
  1078. cbBytes = (cchProfSize * sizeof(TCHAR));
  1079. lStatus = RegQueryValueEx(hkeyUser,TEXT("ProfileImagePath"), NULL, &dwType,
  1080. (LPBYTE)lpProfilePath, &cbBytes);
  1081. if (lStatus == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
  1082. {
  1083. // Return just the directory name portion of the profile path
  1084. //lstrcpyn(lpBuff, PathFindFileName(lpProfilePath), iSize);
  1085. LocalFree(pUser);
  1086. LocalFree(pTextSid);
  1087. RegCloseKey(hkeyProfileList);
  1088. RegCloseKey(hkeyUser);
  1089. return TRUE;
  1090. }
  1091. else
  1092. {
  1093. // Have exhausted our resources -- can't get the
  1094. // profile path.
  1095. LocalFree(pUser);
  1096. LocalFree(pTextSid);
  1097. RegCloseKey(hkeyProfileList);
  1098. RegCloseKey(hkeyUser);
  1099. return FALSE;
  1100. }
  1101. }
  1102. }
  1103. else
  1104. {
  1105. // Couldn't open reg key so we're hosed
  1106. LocalFree(pUser);
  1107. LocalFree(pTextSid);
  1108. RegCloseKey(hkeyProfileList);
  1109. return FALSE;
  1110. }
  1111. }
  1112. LocalFree(pUser);
  1113. LocalFree(pTextSid);
  1114. }
  1115. else
  1116. {
  1117. // For some completely unknown reason we have a NULL Sid string
  1118. // so we're doomed.
  1119. LocalFree(pTextSid);
  1120. return FALSE;
  1121. }
  1122. // We should never fall through to this point but if we do...
  1123. return FALSE;
  1124. }
  1125. //+--------------------------------------------------------------------------
  1126. //
  1127. // Function: GetTextualSid()
  1128. //
  1129. // Synopsis: WINNT only -- converts a SID to text.
  1130. //
  1131. // Returns: TRUE if successful, FALSE if not.
  1132. // Sets LastError on failure.
  1133. //
  1134. // Taken from the January 1998 MSDN reference.
  1135. //
  1136. //---------------------------------------------------------------------------
  1137. BOOL GetTextualSid( PSID pSid, // binary Sid
  1138. LPTSTR TextualSid, // buffer for Textual representation of Sid
  1139. LPDWORD lpdwBufferLen) // required/provided TextualSid buffersize
  1140. {
  1141. PSID_IDENTIFIER_AUTHORITY psia;
  1142. DWORD dwSubAuthorities;
  1143. DWORD dwSidRev=SID_REVISION;
  1144. DWORD dwCounter;
  1145. DWORD dwSidSize;
  1146. // Validate the binary SID.
  1147. if(!IsValidSid(pSid))
  1148. {
  1149. SetLastError(ERROR_INVALID_PARAMETER);
  1150. return FALSE;
  1151. }
  1152. // Get the identifier authority value from the SID.
  1153. psia = GetSidIdentifierAuthority(pSid);
  1154. // Get the number of subauthorities in the SID.
  1155. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  1156. // Compute the buffer length.
  1157. // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
  1158. dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  1159. // Check input buffer length.
  1160. // If too small, indicate the proper size and set last error.
  1161. if (*lpdwBufferLen < dwSidSize)
  1162. {
  1163. *lpdwBufferLen = dwSidSize;
  1164. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1165. return FALSE;
  1166. }
  1167. // Add 'S' prefix and revision number to the string.
  1168. dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
  1169. // Add SID identifier authority to the string.
  1170. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  1171. {
  1172. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  1173. TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  1174. (USHORT)psia->Value[0],
  1175. (USHORT)psia->Value[1],
  1176. (USHORT)psia->Value[2],
  1177. (USHORT)psia->Value[3],
  1178. (USHORT)psia->Value[4],
  1179. (USHORT)psia->Value[5]);
  1180. }
  1181. else
  1182. {
  1183. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  1184. TEXT("%lu"),
  1185. (ULONG)(psia->Value[5] ) +
  1186. (ULONG)(psia->Value[4] << 8) +
  1187. (ULONG)(psia->Value[3] << 16) +
  1188. (ULONG)(psia->Value[2] << 24) );
  1189. }
  1190. // Add SID subauthorities to the string.
  1191. //
  1192. for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  1193. {
  1194. dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
  1195. *GetSidSubAuthority(pSid, dwCounter) );
  1196. }
  1197. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1198. return TRUE;
  1199. }
  1200. extern "C" VOID BuildNTJobName(LPTSTR lpJobName)
  1201. {
  1202. TCHAR szUser[MAX_PATH];
  1203. TCHAR szDomain[MAX_PATH];
  1204. TCHAR szProfile[MAX_PATH];
  1205. LPTSTR Current;
  1206. LPTSTR Dot;
  1207. if (!lpJobName) return; // Null pointers not allowed.
  1208. if (!GetCurrentUser(szUser, ARRAYSIZE(szUser),
  1209. szDomain, ARRAYSIZE(szDomain),
  1210. szProfile, ARRAYSIZE(szProfile)))
  1211. {
  1212. // GetCurrentUser failed so bail out.
  1213. return;
  1214. }
  1215. // Walk to the end of the lpJobName string
  1216. Dot = lpJobName;
  1217. while (*Dot) Dot = CharNext(Dot);
  1218. // Dot now points to the end of the lpJobName string. Backup until
  1219. // we get to the "dot" in the extension.
  1220. Dot = CharPrev(lpJobName, Dot);
  1221. while ((Dot > lpJobName) && (*Dot != TEXT('.'))) Dot = CharPrev(lpJobName, Dot);
  1222. // Ok truncate the extension by putting a NULL on the "dot".
  1223. *Dot = TEXT('\0');
  1224. // Walk to the end of the szProfile string
  1225. Current = szProfile;
  1226. while (*Current) Current = CharNext(Current);
  1227. // Current now points to the end of szProfile. Backup until we get
  1228. // to the first "\".
  1229. Current = CharPrev(szProfile, Current);
  1230. while ((Current > szProfile) && (*Current != TEXT('\\'))) Current = CharPrev(szProfile, Current);
  1231. *Current = TEXT('(');
  1232. lstrcat(lpJobName, TEXT(" "));
  1233. lstrcat(lpJobName, Current);
  1234. lstrcat(lpJobName, TEXT(").JOB"));
  1235. }
  1236. extern "C" BOOL IsUserAdmin(VOID)
  1237. /*++
  1238. Routine Description:
  1239. This routine returns TRUE if the caller's process is a
  1240. member of the Administrators local group.
  1241. Caller is NOT expected to be impersonating anyone and IS
  1242. expected to be able to open their own process and process
  1243. token.
  1244. Arguments:
  1245. None.
  1246. Return Value:
  1247. TRUE - Caller has Administrators local group.
  1248. FALSE - Caller does not have Administrators local group.
  1249. --*/
  1250. {
  1251. HANDLE Token;
  1252. DWORD BytesRequired;
  1253. PTOKEN_GROUPS Groups;
  1254. BOOL b;
  1255. DWORD i;
  1256. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1257. PSID AdministratorsGroup;
  1258. //
  1259. // On non-NT platforms the user is administrator.
  1260. //
  1261. if(!IsPlatformNT()) {
  1262. return(TRUE);
  1263. }
  1264. //
  1265. // Open the process token.
  1266. //
  1267. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  1268. return(FALSE);
  1269. }
  1270. b = FALSE;
  1271. Groups = NULL;
  1272. //
  1273. // Get group information.
  1274. //
  1275. if (!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  1276. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  1277. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
  1278. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired))
  1279. {
  1280. b = AllocateAndInitializeSid(
  1281. &NtAuthority,
  1282. 2,
  1283. SECURITY_BUILTIN_DOMAIN_RID,
  1284. DOMAIN_ALIAS_RID_ADMINS,
  1285. 0, 0, 0, 0, 0, 0,
  1286. &AdministratorsGroup
  1287. );
  1288. if (b) {
  1289. //
  1290. // See if the user has the administrator group.
  1291. //
  1292. b = FALSE;
  1293. for(i=0; i<Groups->GroupCount; i++) {
  1294. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  1295. b = TRUE;
  1296. break;
  1297. }
  1298. }
  1299. FreeSid(AdministratorsGroup);
  1300. }
  1301. }
  1302. //
  1303. // Clean up and return.
  1304. //
  1305. if(Groups) {
  1306. LocalFree((HLOCAL)Groups);
  1307. }
  1308. CloseHandle(Token);
  1309. return(b);
  1310. }