SA.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:28k
源码类别:

Windows编程

开发平台:

Visual C++

  1. // ===========================================================================
  2. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. // PARTICULAR PURPOSE.
  6. //
  7. // Copyright 1997 Microsoft Corporation.  All Rights Reserved.
  8. // ===========================================================================
  9. //
  10. //+--------------------------------------------------------------------------
  11. //
  12. // File:        sa.cpp
  13. //
  14. // Contents:    All code needed to build the simple job submission tool
  15. //
  16. // Purpose:     Demonstration of calls to methods of the following new
  17. //              interfaces:
  18. //                  1. ITaskScheduler
  19. //                  2. ITask
  20. //                  3. ITaskTrigger
  21. //                  4. IEnumWorkItems
  22. //
  23. // Comments:    This application is similar in functionality to
  24. //              the "AT" command provided with Windows NT.  However,
  25. //              the AT command functions through the NetSchedule APIs,
  26. //              as opposed to the COM interfaces demonstrated here.
  27. //
  28. //              The Task Scheduler replaces ATSVC.EXE and implements
  29. //              those APIs as a restricted subset of the new ones
  30. //              demonstrated here.
  31. //
  32. //              On Win9x systems, the Task Scheduler replaces
  33. //              the System Agent, providing more flexible and reliable
  34. //              scheduling options than previously available.
  35. //              However, although the SAGE jobs are converted
  36. //              to Task Scheduler work items, the actual
  37. //              SAGE API has been abandoned and is not implemented.
  38. //
  39. //              The Task Scheduler APIs provide a greater degree of
  40. //              freedom and robustness than those APIs.  This code
  41. //              demonstrates a stripped version of AT rewritten to
  42. //              use the new APIs.
  43. //
  44. // Additional:  The Task Scheduler service must be running.  It is easily
  45. //              started by the command "net start schedule" if it is not
  46. //              running.  It is also trivial to start it through
  47. //              the service control manager APIs. Doing it in the code
  48. //              directly makes a good enhancement to the program below.
  49. // 
  50. //              Since there is not a service controller on Win9x, 
  51. //              the user may start the service by executing the
  52. //              binary directly from the command line (mstask.exe).
  53. //              Win9x users will see a system tray icon if the service 
  54. //              is running.
  55. //
  56. //              The service may also be started from the folder UI available
  57. //              directly by opening "My Computer" and then opening the 
  58. //              "Scheduled Tasks" folder.  The start command appears on the
  59. //              "Advanced" menu.
  60. //
  61. //              Sample code to start and stop the service, on both 
  62. //              Windows NT and Win9x based systems appears in the
  63. //              documentation.
  64. //
  65. //              If the Task Scheduler service is not running, most 
  66. //              of this program will fail to execute.  If there are 
  67. //              tasks waiting to execute after login, the service 
  68. //              will have been started by default.
  69. //             
  70. //---------------------------------------------------------------------------
  71. #include <wchar.h>
  72. #include <windows.h>
  73. #include <mbctype.h>
  74. #include <initguid.h>
  75. #include <mstask.h>
  76. #include <msterr.h>
  77. //+--------------------------------------------------------------------------
  78. // Global variables
  79. //---------------------------------------------------------------------------
  80. ITaskScheduler *g_pITaskScheduler = NULL;
  81. //+--------------------------------------------------------------------------
  82. // Function Prototypes
  83. //---------------------------------------------------------------------------
  84. HRESULT Init(void);
  85. void Cleanup(void);
  86. void DisplayHelp(LPWSTR);
  87. HRESULT EnumerateJobs(void);
  88. HRESULT DeleteJob(LPWSTR);
  89. HRESULT AddJob(LPWSTR, LPSYSTEMTIME, LPWSTR, LPWSTR, LPWSTR);
  90. HRESULT ConvertToSystemTime(LPWSTR, LPSYSTEMTIME);
  91. //+--------------------------------------------------------------------------
  92. //
  93. // Function:        main
  94. //
  95. // Synopsis:        Entry point for code.  Parses command line,
  96. //                  and calls appropriate subfunction as a result.
  97. //
  98. //  Arguments:      See DisplayHelp().  Uses argv, argc to get 
  99. //                  command line args.
  100. //
  101. //  Returns:        S_OK for success or the failure code for failure.
  102. //
  103. //---------------------------------------------------------------------------
  104. LONG _CRTAPI1 main (int argc, char **argv)
  105. {
  106.     HRESULT hr = S_OK;
  107.     UINT uCodePage;
  108.     char *lpcszDeleteFlag = "/DELETE";
  109.     WCHAR lpwszJobName[255], lpwszTime[32];
  110.     WCHAR lpwszUserName[64], lpwszPassword[64], lpwszCommand[255];
  111.     WCHAR lpwszProgName[255];
  112.     SYSTEMTIME tTime;
  113.     // For protection
  114.     g_pITaskScheduler = NULL;
  115.     // String conversion initialization
  116.     uCodePage = _getmbcp();
  117.    
  118.     MultiByteToWideChar(uCodePage, 0, argv[0],
  119.                         -1, lpwszProgName,
  120.                         255);
  121.     // Check number of command line arguments.
  122.     //      1 argument      =   enumerate work items 
  123.     //      2 args          =   display help (don't init OLE)
  124.     //      3 args          =   delete work item 
  125.     //      4, 5 or 6 args  =   add a work item 
  126.     //      all others      =   error, display help
  127.     if ((argc == 2) || (argc > 6))
  128.     {
  129.         DisplayHelp(lpwszProgName);
  130.         return hr;
  131.     }
  132.     // Attempt to initialize OLE and fill in the global g_pITaskScheduler
  133.     hr = Init();
  134.     if (FAILED(hr))
  135.     {
  136.         wprintf(L"Error: OLE initialization and instantiation failedn");
  137.         return hr;
  138.     }
  139.     
  140.     switch(argc)
  141.     {
  142.         case 1:
  143.             // User would like to enumerate work items 
  144.             hr = EnumerateJobs();
  145.             break;
  146.         case 3:
  147.             if (! lstrcmpiA(argv[2], lpcszDeleteFlag))
  148.             {
  149.                 // User would like to delete work item in argv[1]
  150.                 MultiByteToWideChar(uCodePage, 0, argv[1], 
  151.                                     -1, lpwszJobName,
  152.                                     255);
  153.                 hr = DeleteJob(lpwszJobName);
  154.             }
  155.             else
  156.             {
  157.                 // User has made an error in command line args                
  158.                 
  159.                 wprintf(L"Error: Must be %s taskname.job /DELETEn", lpwszProgName);
  160.                 wprintf(L"n %s /?  for more help.n", lpwszProgName);
  161.                 
  162.                 Cleanup();
  163.                 return E_FAIL;
  164.             }
  165.             break;
  166.         case 4:
  167.         case 5:
  168.         case 6:
  169.             // User would like to add a work item.  The following
  170.             // argument cases apply:
  171.             //      4 - User has specified work item name, but not given 
  172.             //          username or password.  Will prompt later.
  173.             //      5 - User has specified work item name and username,
  174.             //          but no password.  Will prompt later.            
  175.             //      6 - User has specified all information.
  176.             
  177.                 uCodePage = _getmbcp();
  178.     
  179.                 MultiByteToWideChar(uCodePage, 0, argv[1], 
  180.                                     -1, lpwszJobName,
  181.                                     255);
  182.                 MultiByteToWideChar(uCodePage, 0, argv[2],
  183.                                     -1, lpwszTime,
  184.                                     32);
  185.             hr = ConvertToSystemTime(lpwszTime, &tTime);
  186.             if (FAILED(hr))
  187.             {
  188.                 wprintf(L"Error: Conversion of command line time to system time failed.n");
  189.                 Cleanup();
  190.                 return hr;
  191.             }
  192.             
  193.             *lpwszUserName = L'';
  194.             *lpwszPassword = L'';
  195.             MultiByteToWideChar(uCodePage, 0, argv[3],
  196.                                 -1, lpwszCommand,
  197.                                 255);
  198.             if (argc > 4)
  199.             {
  200.                 MultiByteToWideChar(uCodePage, 0, argv[4],
  201.                                     -1, lpwszUserName,
  202.                                     64);
  203.             }
  204.             if (argc == 6)
  205.             {
  206.                 MultiByteToWideChar(uCodePage, 0, argv[5],
  207.                                     -1, lpwszPassword,
  208.                                     64);
  209.             }
  210.             
  211.             hr = AddJob(lpwszJobName, &tTime, lpwszCommand, lpwszUserName, lpwszPassword);
  212.             
  213.             break;
  214.         default:
  215.             hr = E_FAIL;
  216.             DisplayHelp(lpwszProgName);
  217.     }
  218.     
  219.     Cleanup();
  220.     return hr;
  221. }
  222. //+--------------------------------------------------------------------------
  223. //
  224. // Function:        Init()
  225. //
  226. // Synopsis:        Called to initialize and instantiate a task 
  227. //                  scheduler object.
  228. //
  229. // Arguments:       none (void)
  230. //
  231. // Returns:         HRESULT indicating success or failure.  S_OK on success.
  232. //
  233. // Side effect:     Sets global pointer g_pITaskScheduler, for use in other
  234. //                  functions.  
  235. //
  236. //---------------------------------------------------------------------------
  237. HRESULT Init()
  238. {
  239.     HRESULT hr = S_OK;
  240.     // Bring in the library
  241.     hr = CoInitialize(NULL);
  242.     if (FAILED(hr))
  243.     {
  244.         return hr;
  245.     }
  246.     // Create the pointer to Task Scheduler object
  247.     // CLSID from the header file mstask.h
  248.     hr = CoCreateInstance(
  249.         CLSID_CTaskScheduler,
  250.         NULL,
  251.         CLSCTX_INPROC_SERVER,
  252.         IID_ITaskScheduler,
  253.         (void **) &g_pITaskScheduler);
  254.     // Should we fail, unload the library
  255.     if (FAILED(hr))
  256.     {
  257.         CoUninitialize();
  258.     }
  259.     return hr;
  260. }
  261. //+--------------------------------------------------------------------------
  262. //
  263. // Function:    Cleanup()
  264. //
  265. // Synopsis:    Called to clean up OLE, memory, etc. before termination
  266. //
  267. // Arguments:   none (void)
  268. //
  269. // Returns:     nothing (void)
  270. //
  271. // Side effect: Cancels the global pointer g_pITaskScheduler.
  272. //
  273. //---------------------------------------------------------------------------
  274. void Cleanup()
  275. {
  276.     if (g_pITaskScheduler)
  277.     {
  278.         g_pITaskScheduler->Release();
  279.         g_pITaskScheduler = NULL;
  280.     }
  281.    
  282.     // Unload the library, now that our pointer is freed.
  283.     CoUninitialize();
  284.     return;
  285. }
  286. //+--------------------------------------------------------------------------
  287. //
  288. // Function:    DisplayHelp() 
  289. //
  290. // Synopsis:    Prints out help and usage information
  291. //
  292. // Arguments:   lpwszProgName - a pointer to a WSTR containing argv[0]
  293. //
  294. // Returns:     nothing (void)
  295. //
  296. //---------------------------------------------------------------------------
  297. void DisplayHelp(LPWSTR lpwszProgName)
  298. {
  299.     wprintf(L"%s -- a small program to replicate somen", lpwszProgName); 
  300.     wprintf(L"tfunctionality of the AT command, using then");
  301.     wprintf(L"tnew Task Scheduler interfaces.nn");
  302.     wprintf(L"Usage:n");
  303.     wprintf(L"t%s /?ntttttt- Display this helpn",lpwszProgName);
  304.     wprintf(L"t%sntttttt- Show all work itemsn",lpwszProgName);
  305.     wprintf(L"t%s TaskName.job /DELETE ntttttt- delete work itemn",lpwszProgName);
  306.     wprintf(L"t%s TaskName.job Time Command [UserName [Password]]ntttttt- submit a new work itemnn",lpwszProgName);
  307.     wprintf(L"TaskName.job is the name of the work item object on disk.n");
  308.     wprintf(L"The work item will appear in the Scheduled Tasks folder as TaskNamen");
  309.     wprintf(L"but must be given the extension ".job" for the service n");
  310.     wprintf(L"to recognize and run it.nn");
  311.     wprintf(L"Task Time is in 24 hour format (such as 15:30) and is then");
  312.     wprintf(L"next instance of this time within 24 hours.nn");
  313.     
  314.     wprintf(L"The Command should contain the name of the executable to run.n");
  315.     wprintf(L"Note that the pathname may NOT contain spaces.  If then");
  316.     wprintf(L"program requires command line parameters, enclose the entiren");
  317.     wprintf(L"command string in quotation marks.nn");
  318.     wprintf(L"Username and password are required to run the specified work item under Windows NT.n");
  319.     wprintf(L"Under Windows NT, if not specified, you will be prompted.n");
  320.     wprintf(L"Under Windows 95, both fields are ignored.  If not specifiedn");
  321.     wprintf(L"on the command line, you will not be prompted.nn");
  322.     
  323.     return;
  324. }
  325.  
  326. //+--------------------------------------------------------------------------
  327. //
  328. // Function:    EnumerateJobs()
  329. //
  330. // Synopsis:    Goes through all scheduled work items on a system and 
  331. //              lists them, along with a short trigger string.
  332. //
  333. // Arguments:   none (void).  Requires g_pITaskScheduler.
  334. //
  335. // Returns:     HRESULT indicating success (S_OK) or other.
  336. //
  337. //---------------------------------------------------------------------------
  338. HRESULT EnumerateJobs()
  339. {
  340.     HRESULT hr = S_OK, hrLoop = S_OK;
  341.     IEnumWorkItems *pIEnumWorkItems;
  342.     IUnknown *pIU;
  343.     ITask *pITask;
  344.     ULONG ulTasksToGet = 1, ulActualTasksRetrieved = 0;
  345.     LPWSTR *rgpwszNames, pwszTrigger;
  346.     WORD wTrigCount = 0;
  347.     WORD wTemp;
  348.     
  349.     //
  350.     // Get an enumeration pointer, using ITaskScheduler::Enum
  351.     //
  352.     hr = g_pITaskScheduler->Enum(&pIEnumWorkItems);
  353.     if (FAILED(hr))
  354.     {
  355.         wprintf(L"Failed to get enumeratorn");
  356.         return hr;
  357.     }
  358.     do
  359.     {
  360.         // Get a single work item, using IEnumWorkItems::Next
  361.         hrLoop = pIEnumWorkItems->Next(ulTasksToGet, &rgpwszNames,
  362.                                        &ulActualTasksRetrieved);
  363.         if (hrLoop == S_FALSE)
  364.         {
  365.             // There are no more waiting tasks to look at
  366.             break;
  367.         }
  368.         // Attach to the work item, using ITaskScheduler::Activate
  369.         hr = g_pITaskScheduler->Activate(rgpwszNames[0], IID_ITask, &pIU);
  370.         if (FAILED(hr))
  371.         {
  372.             wprintf(L"Error: Activate Failedn",hr);
  373.             break;
  374.         }
  375.         // QI pIU for pITask
  376.    
  377.         hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
  378.         pIU->Release();
  379.         pIU = NULL;
  380.         if (FAILED(hr))
  381.         {
  382.             wprintf(L"Error: QI for ITask failed in Activate.n");
  383.             break;
  384.         }
  385.         // Display task name
  386.         wprintf(L"Task: %sn",rgpwszNames[0]); 
  387.         // Use ITask::GetTriggerCount to get count of triggers
  388.         hr = pITask->GetTriggerCount(&wTrigCount);
  389.         if (FAILED(hr))
  390.         {
  391.             wprintf(L"Error: Failed to count triggersn");
  392.             pITask->Release();
  393.             break;
  394.         }
  395.         
  396.         for (wTemp = 0; wTemp < wTrigCount; wTemp++)
  397.         {
  398.             // Dump Triggers using ITask::GetTriggerString
  399.             hr = pITask->GetTriggerString(wTemp, &pwszTrigger);
  400.             if (FAILED(hr))
  401.             {
  402.                 wprintf(L"Error: Failed to get trigger stringn");
  403.                 pITask->Release();
  404.                 break;
  405.             }
  406.             wprintf(L"tTrigger: %sn",pwszTrigger);
  407.             // Clean up the memory we were allocated for trig string
  408.             CoTaskMemFree(pwszTrigger);
  409.         }
  410.         // Clean up each element in the array of job names, then
  411.         // clean up the final array.
  412.         CoTaskMemFree(rgpwszNames[0]);
  413.         CoTaskMemFree(rgpwszNames);
  414.         
  415.         // Free the ITask pointer
  416.     
  417.         pITask->Release();
  418.     } while(1);
  419.     // Release the enumeration pointer
  420.     
  421.     pITask = NULL;
  422.     pIEnumWorkItems->Release();
  423.     pIEnumWorkItems = NULL;
  424.     return hr; 
  425. }    
  426.     
  427. //+--------------------------------------------------------------------------
  428. //
  429. // Function:        DeleteJob()
  430. //
  431. // Synopsis:        Deletes a work item from the Scheduled Tasks folder.
  432. //
  433. // Arguments:       lpwszJobName - the name of the work item to delete
  434. //
  435. // Returns:         HRESULT indicating success (S_OK) or failure.
  436. //
  437. //---------------------------------------------------------------------------
  438. HRESULT DeleteJob(LPWSTR lpwszJobName)
  439. {
  440.     HRESULT hr = S_OK;
  441.     hr = g_pITaskScheduler->Delete(lpwszJobName);
  442.     return hr;
  443. }
  444. //+--------------------------------------------------------------------------
  445. //
  446. // Function:        AddJob()
  447. //
  448. // Synopsis:        Adds a new work item to the Scheduled Tasks folder.
  449. //
  450. // Arguments:       lpwszJobName - name of the task file
  451. //                  lptTime      - pointer to SYSTEMTIME struct containing
  452. //                                      the time the job should run.
  453. //                  lpwszCommand - name of application (command) to run.
  454. //                  lpwszUserName- user name to run job under
  455. //                  lpwszPassword- password for that user
  456. //
  457. // Returns:         HRESULT indicating success (S_OK) or failure.
  458. //
  459. // Notes:           The password or BOTH the username and password
  460. //                  may be passed in as '' strings, in which case
  461. //                  this function will prompt on stdout for password
  462. //                  and username
  463. //
  464. //---------------------------------------------------------------------------
  465. HRESULT AddJob(LPWSTR lpwszJobName, LPSYSTEMTIME lptTime,
  466.                 LPWSTR lpwszCommand, LPWSTR lpwszUserName,
  467.                 LPWSTR lpwszPassword)
  468. {
  469.     HRESULT hr = S_OK;
  470.     IUnknown *pIU;
  471.     IPersistFile *pIPF;
  472.     ITask *pITask;
  473.     ITaskTrigger *pITaskTrig;
  474.     DWORD dwTaskFlags, dwTrigFlags;
  475.     WORD wTrigNumber;
  476.     TASK_TRIGGER TaskTrig;
  477.     WCHAR lpwszAppName[255];
  478.     int i;
  479.     
  480.     // Add the task.  Most likely failure is that work item already exists.
  481.     // Uses ITaskScheduler::NewWorkItem
  482.     hr = g_pITaskScheduler->NewWorkItem(lpwszJobName, 
  483.                                         CLSID_CTask, 
  484.                                         IID_ITask, 
  485.                                         &pIU);
  486.     if (FAILED(hr))
  487.     {
  488.         wprintf(L"Error:  Create New Task failuren");
  489.         return hr;
  490.     }
  491.     // We now have an IUnknown pointer.  This is queried for an ITask
  492.     // pointer on the work item we just added.
  493.     
  494.     hr = pIU->QueryInterface(IID_ITask, (void **) &pITask);
  495.     if (FAILED(hr))
  496.     {
  497.         wprintf(L"Error: IUnknown failed to yield ITaskn");
  498.         pIU->Release();
  499.         return hr;
  500.     }
  501.     
  502.     // Cleanup pIUnknown, as we are done with it.
  503.     
  504.     pIU->Release();
  505.     pIU = NULL;
  506.     //
  507.     // We need to see if we support security, and we
  508.     // do this by calling ITask::SetAccountInformation
  509.     // and checking if the failure code is SCHED_E_NO_SECURITY_SERVICES
  510.     //
  511.     hr = pITask->SetAccountInformation(lpwszUserName, lpwszPassword);
  512.     if (hr != SCHED_E_NO_SECURITY_SERVICES)
  513.     {
  514.     
  515.         // Check to see if username is null
  516.         if (*lpwszPassword == L'')
  517.         {
  518.             // If password was null, chance username is, too.
  519.             if (*lpwszUserName == L'')
  520.             {
  521.                 wprintf(L"Enter username to run job %s as: ",lpwszJobName);
  522.                 wscanf(L"%s",lpwszUserName);
  523.                 wprintf(L"n");
  524.             }
  525.     
  526.             wprintf(L"Enter password to user %s: ",lpwszUserName);
  527.             wscanf(L"%s",lpwszPassword);
  528.             wprintf(L"n");
  529.         }
  530.     }
  531.     // Set the account information using ITask::SetAccountInformation
  532.     // This fails for Win9x, but we ignore the failure.
  533.     hr = pITask->SetAccountInformation(lpwszUserName, lpwszPassword);
  534.     if ((FAILED(hr)) && (hr != SCHED_E_NO_SECURITY_SERVICES))
  535.     {
  536.         wprintf(L"Error: Failed to set credentials on task object %xn",hr);
  537.         pITask->Release();
  538.         return hr;
  539.     }
  540.     // Extract parameters from the application name
  541.     // Note that there might not be any parameters at all.
  542.     // We butcher a path like C:Program Filesfoo.exe, because
  543.     // we break on space, but this is ok, because user could say
  544.     // C:progra~1foo.exe instead.
  545.     i = 0;
  546.     while ((*lpwszCommand != L' ') && (*lpwszCommand != ''))
  547.     {
  548.         lpwszAppName[i] = *lpwszCommand;
  549.         i++;
  550.         lpwszCommand++;
  551.     }
  552.     lpwszAppName[i] = L'';
  553.     if (*lpwszCommand == L' ')
  554.     {
  555.         lpwszCommand++;
  556.     }
  557.     
  558.     // Set command name with ITask::SetApplicationName
  559.     hr = pITask->SetApplicationName(lpwszAppName);
  560.     if (FAILED(hr))
  561.     {
  562.         wprintf(L"Error: Failed to set command name (with parms)n"); 
  563.         pITask->Release();
  564.         return hr;
  565.     }
  566.     // Set task parameters with ITask::SetParameters
  567.     hr = pITask->SetParameters(lpwszCommand);
  568.     if (FAILED(hr))
  569.     {
  570.         wprintf(L"Error: Failed to set parametersn");
  571.         pITask->Release();
  572.         return hr;
  573.     }
  574.         
  575.     // Set the comment, so we know how this job go there
  576.     // Uses ITask::SetComment
  577.     hr = pITask->SetComment(L"This scheduled task created by command line SDK sample tool");
  578.     if (FAILED(hr))
  579.     {
  580.         wprintf(L"Error: Task comment could not be setn");
  581.         pITask->Release();
  582.         return hr;
  583.     }
  584.     // Set the flags on the task object
  585.     // Use ITask::SetFlags
  586.     dwTaskFlags = TASK_FLAG_DELETE_WHEN_DONE;
  587.     hr = pITask->SetFlags(dwTaskFlags);
  588.     if (FAILED(hr))
  589.     {
  590.         wprintf(L"Error: Could not set task flagsn");
  591.         pITask->Release();
  592.         return hr;
  593.     }
  594.     // Now, create a trigger to run the task at our specified time.
  595.     // Uses ITask::CreateTrigger()
  596.     hr = pITask->CreateTrigger(&wTrigNumber, &pITaskTrig);
  597.     if (FAILED(hr))
  598.     {
  599.         wprintf(L"Error: Could not create a new triggern");
  600.         pITask->Release();
  601.         return hr;
  602.     }
  603.     // Now, fill in the trigger as necessary.
  604.     dwTrigFlags = 0;
  605.     TaskTrig.cbTriggerSize = sizeof(TASK_TRIGGER);
  606.     TaskTrig.Reserved1 = 0;
  607.     TaskTrig.wBeginYear = lptTime->wYear;
  608.     TaskTrig.wBeginMonth = lptTime->wMonth;
  609.     TaskTrig.wBeginDay = lptTime->wDay;
  610.     TaskTrig.wEndYear = 0;
  611.     TaskTrig.wEndMonth = 0;
  612.     TaskTrig.wEndDay = 0;
  613.     TaskTrig.wStartHour = lptTime->wHour;
  614.     TaskTrig.wStartMinute = lptTime->wMinute;
  615.     TaskTrig.MinutesDuration = 0;
  616.     TaskTrig.MinutesInterval = 0;
  617.     TaskTrig.rgFlags = dwTrigFlags;
  618.     TaskTrig.TriggerType = TASK_TIME_TRIGGER_ONCE;
  619.     TaskTrig.wRandomMinutesInterval = 0;
  620.     TaskTrig.Reserved2 = 0;
  621.     // Add this trigger to the task using ITaskTrigger::SetTrigger
  622.     hr = pITaskTrig->SetTrigger(&TaskTrig);
  623.     if (FAILED(hr))
  624.     {
  625.         wprintf(L"Error: Failed to set trigger to desired valuesn");
  626.         pITaskTrig->Release();
  627.         pITask->Release();
  628.         return hr;
  629.     }
  630.     // Make the changes permanent
  631.     // Requires using IPersistFile::Save()
  632.     hr = pITask->QueryInterface(IID_IPersistFile, (void **) &pIPF); 
  633.     if (FAILED(hr))
  634.     {
  635.         wprintf(L"Error: Could not get IPersistFile on taskn");
  636.         pITaskTrig->Release();
  637.         pITask->Release();
  638.         return hr;
  639.     }
  640.     hr = pIPF->Save(NULL, FALSE);
  641.     if (FAILED(hr))
  642.     {
  643.         wprintf(L"Error: Could not save objectn");
  644.         pITaskTrig->Release();
  645.         pITask->Release();
  646.         pIPF->Release();
  647.         return hr;
  648.     }
  649.     // We no longer need ITask
  650.     
  651.     pITask->Release();
  652.     pITask = NULL;
  653.     // Done with ITaskTrigger pointer
  654.     
  655.     pITaskTrig->Release();
  656.     pITaskTrig = NULL;
  657.     // Done with IPersistFile
  658.     
  659.     pIPF->Release();
  660.     pIPF = NULL;
  661.     return hr;
  662. //+--------------------------------------------------------------------------
  663. //
  664. // Function:        ConvertToSystemTime()
  665. //
  666. // Synopsis:        Given a text string from the command line of the form
  667. //                  XX:YY where XX = 0 - 23, and YY = 0 - 59,
  668. //                  obtain the next instance in 24 hours of said time
  669. //                  and return this time in a SYSTEMTIME structure
  670. //                  so that it can be used to set triggers
  671. //
  672. // Arguments:       lpwszTime    -   The text string of time
  673. //                  lptTime     -   The SYSTEMTIME pointer
  674. //
  675. // Returns:         HRESULT of success (S_OK) or failure
  676. //
  677. //---------------------------------------------------------------------------
  678. HRESULT ConvertToSystemTime(LPWSTR lpwszTime, LPSYSTEMTIME lptTime)
  679. {
  680.     WORD wMin = 0, wHr = 0, wMaxFeb = 28;
  681.     WCHAR szTemp[3], *szEnd1, *szEnd2;
  682.     SYSTEMTIME tNow;
  683.     int i, j;
  684.     // Extract minutes and hour from string
  685.     if ((wcslen(lpwszTime) > 5) || (wcslen(lpwszTime) < 4))
  686.     {
  687.         wprintf(L"Error: Invalid time string givenn");
  688.         return E_FAIL;
  689.     }
  690.     // Hours first.
  691.     
  692.     i = 0;
  693.     while (*lpwszTime != ':')
  694.     {
  695.         szTemp[i] = *lpwszTime;
  696.         i++;
  697.         if (i > 2)
  698.         {
  699.             // User gave a bad time string
  700.             wprintf(L"Error: Bad hours in time stringn");
  701.             return E_FAIL;
  702.         }
  703.         lpwszTime++;
  704.     }
  705.     szTemp[i] = L'';
  706.     lpwszTime++;
  707.  
  708.     // Convert to value
  709.     wHr = (WORD) wcstoul(szTemp, &szEnd1, 10);
  710.     
  711.     // Now do minutes
  712.  
  713.     i = wcslen(lpwszTime);
  714.     j = 0;
  715.     while (i)
  716.     {
  717.         szTemp[j] = *lpwszTime;
  718.         j++;
  719.         i--;
  720.         lpwszTime++;
  721.     }
  722.     szTemp[j] = L'';
  723.     wMin = (WORD) wcstoul(szTemp, &szEnd2, 10);
  724.     // Now figure out if we are running today or tomorrow
  725.     
  726.     GetLocalTime(&tNow);
  727.     if ((wHr < tNow.wHour) || 
  728.        ((wHr == tNow.wHour) && (wMin < tNow.wMinute)))
  729.     {
  730.         // Job is tomorrow - we must figure out what tomorrow is
  731.         
  732.         switch(tNow.wMonth)
  733.         {
  734.             case 4:
  735.             case 6:
  736.             case 9:
  737.             case 11:
  738.                 // Thirty day months
  739.                 
  740.                 if ((tNow.wDay + 1) > 30)
  741.                 {
  742.                     tNow.wDay = 1;
  743.                     tNow.wMonth++;
  744.                 }
  745.                 else
  746.                 {
  747.                     tNow.wDay++;
  748.                 }
  749.                 break;
  750.             case 2:
  751.                 // February
  752.                 // Leap Year?
  753.                 
  754.                 if ((tNow.wYear % 4) == 0) 
  755.                 {
  756.                     wMaxFeb = 29;
  757.                 }
  758.                 if (((tNow.wYear % 100) == 0) &&
  759.                     ((tNow.wYear % 400) != 0))
  760.                 {
  761.                     wMaxFeb = 28;
  762.                 }
  763.                 if ((tNow.wDay + 1) > wMaxFeb)
  764.                 {
  765.                     tNow.wDay = 1;
  766.                     tNow.wMonth++;
  767.                 }
  768.                 else
  769.                 {
  770.                     tNow.wDay++;
  771.                 }
  772.                 break;
  773.             default:
  774.                 // 31 day months.  Handle Dec. later
  775.                 
  776.                 if ((tNow.wDay + 1) > 31)
  777.                 {
  778.                     tNow.wDay = 1;
  779.                     tNow.wMonth++;
  780.                 }
  781.                 else
  782.                 {
  783.                     tNow.wDay++;
  784.                 }
  785.                 
  786.                 if (tNow.wMonth > 12)
  787.                 {
  788.                     tNow.wMonth = 1;
  789.                     tNow.wYear++;
  790.                 }
  791.         }
  792.     }
  793.     if ((wMin < 0) || (wMin > 59))
  794.     {
  795.         wprintf(L"Error: Invalid minutes (need 0 - 59)n");
  796.         return E_FAIL;
  797.     }
  798.     else
  799.     {
  800.         tNow.wMinute = wMin;
  801.     }
  802.     if ((wHr < 0) || (wHr > 23))
  803.     {
  804.         wprintf(L"Error: Invalid hours (need 0 - 23)n");
  805.         return E_FAIL;
  806.     }
  807.     else
  808.     {
  809.         tNow.wHour = wHr;
  810.     }
  811.     lptTime->wHour = tNow.wHour;
  812.     lptTime->wMinute = tNow.wMinute;
  813.     lptTime->wYear = tNow.wYear;
  814.     lptTime->wMonth = tNow.wMonth;
  815.     lptTime->wDay = tNow.wDay;
  816.     lptTime->wDayOfWeek = 0;
  817.     lptTime->wSecond = 0;
  818.     lptTime->wMilliseconds = 0;
  819.     return S_OK;