M
Martin
I occasionally create a number of tasks via the ITaskScheduler
interface and then Run them immediately. For some reason, even though
Windows returns a successful response to the Run request, a task
occasionally fails to start up. No error code is ever given.
I've pulled together the essence of the VC++ program below. Take a look
and see if you have any ideas (other than suggesting the SDK is
flawed)! Note that you have to fill in the username and password at
the bottom before running it, as well as install a do-nothing program
named test1.exe into one of the directories in your path.
By default the program below, when compiled, will create 50 scheduled
tasks and try to run each one immediately. Note afterwards that some
of the tasks never run. Why??? By the way, I have tried this on a
slow system and a fast system, both running Windows XP with SP2.
/Martin
// testsched.cpp : Defines the entry point for the console application.
#include <stdio.h>
#include <mstask.h>
#include <sys/timeb.h>
const int MAX_NAME_LENGTH = 1024;
/********************************************************************
*
* FUNCTION: PersistTask
*
* DESCRIPTION: Calls QueryInterface to get a pointer to IPersistFile
* then IPersistFile::Save to save the task info. to disk.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT PersistTask(ITask * const pITask)
{
HRESULT hr;
IPersistFile *pIPersistFile;
hr = pITask->QueryInterface(IID_IPersistFile,
(void **)&pIPersistFile);
if (FAILED(hr))
{
return hr;
}
hr = pIPersistFile->Save(NULL,
TRUE);
pIPersistFile->Release();
return hr;
}
/********************************************************************
*
* FUNCTION: CreateSchedItem
*
* DESCRIPTION: This function creates a new task for the scheduler.
* To run it or set up a trigger use one of the other
* functions below.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT CreateSchedItem(const char *lpszTaskName,
const char *lpszAppName,
const char *lpszParms,
const char *lpszUserName,
const char *lpszPassword)
{
HRESULT hr = S_OK;
ITaskScheduler *pITS;
/////////////////////////////////////////////////////////////////
// Call CoInitialize to initialize the COM library and then
// CoCreateInstance to get the Task Scheduler object.
/////////////////////////////////////////////////////////////////
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
}
else
{
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITaskScheduler::NewWorkItem to create new task.
/////////////////////////////////////////////////////////////////
wchar_t *lpwc = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszTaskName, MAX_NAME_LENGTH);
ITask *pITask;
hr = pITS->NewWorkItem(lpwc, // Name of task
CLSID_CTask, // Class identifier
IID_ITask, // Interface
identifier
(IUnknown**)&pITask); // Address of task
interface
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
pITS->Release(); // release the scheduler
/////////////////////////////////////////////////////////////////
// Call ITask::SetApplicationName to associate an application with
the task
/////////////////////////////////////////////////////////////////
mbstowcs(lpwc, lpszAppName, MAX_NAME_LENGTH);
hr = pITask->SetApplicationName(lpwc);
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITask::SetParameters to associate an application with the
task
/////////////////////////////////////////////////////////////////
mbstowcs(lpwc, lpszParms, MAX_NAME_LENGTH);
hr = pITask->SetParameters(lpwc);
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITask::SetAccountInformation
/////////////////////////////////////////////////////////////////
wchar_t *lpwc2 = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszUserName, MAX_NAME_LENGTH);
mbstowcs(lpwc2, lpszPassword, MAX_NAME_LENGTH);
hr = pITask->SetAccountInformation(lpwc, lpwc2);
delete [] lpwc; // Don't need name any more.
delete [] lpwc2; // Ditto
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
hr = PersistTask(pITask);
pITask->Release();
CoUninitialize();
return hr;
}
/********************************************************************
*
* FUNCTION: RunSchedItem
*
* DESCRIPTION: This function runs the task immediately.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT RunSchedItem(const char *lpszTaskName)
{
HRESULT hr = S_OK;
ITaskScheduler *pITS;
/////////////////////////////////////////////////////////////////
// Call CoInitialize to initialize the COM library and then
// CoCreateInstance to get the Task Scheduler object.
/////////////////////////////////////////////////////////////////
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
}
else
{
return hr;
}
///////////////////////////////////////////////////////////////////
// Call ITaskScheduler::Activate to get the Task object.
///////////////////////////////////////////////////////////////////
wchar_t *lpwc = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszTaskName, MAX_NAME_LENGTH);
ITask *pITask;
hr = pITS->Activate(lpwc,
IID_ITask,
(IUnknown**) &pITask);
delete [] lpwc; // Don't need name any more.
pITS->Release();
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
///////////////////////////////////////////////////////////////////
// Call ITask::Run to start execution of "Test Task".
///////////////////////////////////////////////////////////////////
hr = pITask->Run();
pITask->Release();
CoUninitialize();
return hr;
}
/********************************************************************
*
* FUNCTION: main
*
* DESCRIPTION: Call CreateSchedItem and RunSchedItem numerous times
*
********************************************************************/
int main(int argc, char* argv[])
{
struct _timeb tstruct;
int icount, iresult;
char ts[20];
// if argument passed in, use it for number of loops else set to 50.
if (argc > 1) icount = atoi(argv[1]);
else icount = 50;
while (icount > 0)
{
_ftime( &tstruct); // Use UTC time in the task name to help figure
things out.
sprintf(ts,"Test
%02u-%02u-%02u-%03u",(tstruct.time%86400)/3600,(tstruct.time%3600)/60,tstruct.time%60,tstruct.millitm);
iresult = CreateSchedItem(ts,"Test1.exe","","***Fill in
Username***","***Fill in password***");
if (iresult != 0) return iresult;
iresult = RunSchedItem(ts);
if (iresult != 0) return iresult;
icount -= 1;
}
return 0;
}
interface and then Run them immediately. For some reason, even though
Windows returns a successful response to the Run request, a task
occasionally fails to start up. No error code is ever given.
I've pulled together the essence of the VC++ program below. Take a look
and see if you have any ideas (other than suggesting the SDK is
flawed)! Note that you have to fill in the username and password at
the bottom before running it, as well as install a do-nothing program
named test1.exe into one of the directories in your path.
By default the program below, when compiled, will create 50 scheduled
tasks and try to run each one immediately. Note afterwards that some
of the tasks never run. Why??? By the way, I have tried this on a
slow system and a fast system, both running Windows XP with SP2.
/Martin
// testsched.cpp : Defines the entry point for the console application.
#include <stdio.h>
#include <mstask.h>
#include <sys/timeb.h>
const int MAX_NAME_LENGTH = 1024;
/********************************************************************
*
* FUNCTION: PersistTask
*
* DESCRIPTION: Calls QueryInterface to get a pointer to IPersistFile
* then IPersistFile::Save to save the task info. to disk.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT PersistTask(ITask * const pITask)
{
HRESULT hr;
IPersistFile *pIPersistFile;
hr = pITask->QueryInterface(IID_IPersistFile,
(void **)&pIPersistFile);
if (FAILED(hr))
{
return hr;
}
hr = pIPersistFile->Save(NULL,
TRUE);
pIPersistFile->Release();
return hr;
}
/********************************************************************
*
* FUNCTION: CreateSchedItem
*
* DESCRIPTION: This function creates a new task for the scheduler.
* To run it or set up a trigger use one of the other
* functions below.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT CreateSchedItem(const char *lpszTaskName,
const char *lpszAppName,
const char *lpszParms,
const char *lpszUserName,
const char *lpszPassword)
{
HRESULT hr = S_OK;
ITaskScheduler *pITS;
/////////////////////////////////////////////////////////////////
// Call CoInitialize to initialize the COM library and then
// CoCreateInstance to get the Task Scheduler object.
/////////////////////////////////////////////////////////////////
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
}
else
{
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITaskScheduler::NewWorkItem to create new task.
/////////////////////////////////////////////////////////////////
wchar_t *lpwc = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszTaskName, MAX_NAME_LENGTH);
ITask *pITask;
hr = pITS->NewWorkItem(lpwc, // Name of task
CLSID_CTask, // Class identifier
IID_ITask, // Interface
identifier
(IUnknown**)&pITask); // Address of task
interface
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
pITS->Release(); // release the scheduler
/////////////////////////////////////////////////////////////////
// Call ITask::SetApplicationName to associate an application with
the task
/////////////////////////////////////////////////////////////////
mbstowcs(lpwc, lpszAppName, MAX_NAME_LENGTH);
hr = pITask->SetApplicationName(lpwc);
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITask::SetParameters to associate an application with the
task
/////////////////////////////////////////////////////////////////
mbstowcs(lpwc, lpszParms, MAX_NAME_LENGTH);
hr = pITask->SetParameters(lpwc);
if (FAILED(hr))
{
CoUninitialize();
delete []lpwc;
return hr;
}
/////////////////////////////////////////////////////////////////
// Call ITask::SetAccountInformation
/////////////////////////////////////////////////////////////////
wchar_t *lpwc2 = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszUserName, MAX_NAME_LENGTH);
mbstowcs(lpwc2, lpszPassword, MAX_NAME_LENGTH);
hr = pITask->SetAccountInformation(lpwc, lpwc2);
delete [] lpwc; // Don't need name any more.
delete [] lpwc2; // Ditto
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
hr = PersistTask(pITask);
pITask->Release();
CoUninitialize();
return hr;
}
/********************************************************************
*
* FUNCTION: RunSchedItem
*
* DESCRIPTION: This function runs the task immediately.
*
* LIMITATIONS: Task name should be fewer than 1024 characters.
*
********************************************************************/
HRESULT RunSchedItem(const char *lpszTaskName)
{
HRESULT hr = S_OK;
ITaskScheduler *pITS;
/////////////////////////////////////////////////////////////////
// Call CoInitialize to initialize the COM library and then
// CoCreateInstance to get the Task Scheduler object.
/////////////////////////////////////////////////////////////////
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
}
else
{
return hr;
}
///////////////////////////////////////////////////////////////////
// Call ITaskScheduler::Activate to get the Task object.
///////////////////////////////////////////////////////////////////
wchar_t *lpwc = new wchar_t[MAX_NAME_LENGTH];
mbstowcs(lpwc, lpszTaskName, MAX_NAME_LENGTH);
ITask *pITask;
hr = pITS->Activate(lpwc,
IID_ITask,
(IUnknown**) &pITask);
delete [] lpwc; // Don't need name any more.
pITS->Release();
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
///////////////////////////////////////////////////////////////////
// Call ITask::Run to start execution of "Test Task".
///////////////////////////////////////////////////////////////////
hr = pITask->Run();
pITask->Release();
CoUninitialize();
return hr;
}
/********************************************************************
*
* FUNCTION: main
*
* DESCRIPTION: Call CreateSchedItem and RunSchedItem numerous times
*
********************************************************************/
int main(int argc, char* argv[])
{
struct _timeb tstruct;
int icount, iresult;
char ts[20];
// if argument passed in, use it for number of loops else set to 50.
if (argc > 1) icount = atoi(argv[1]);
else icount = 50;
while (icount > 0)
{
_ftime( &tstruct); // Use UTC time in the task name to help figure
things out.
sprintf(ts,"Test
%02u-%02u-%02u-%03u",(tstruct.time%86400)/3600,(tstruct.time%3600)/60,tstruct.time%60,tstruct.millitm);
iresult = CreateSchedItem(ts,"Test1.exe","","***Fill in
Username***","***Fill in password***");
if (iresult != 0) return iresult;
iresult = RunSchedItem(ts);
if (iresult != 0) return iresult;
icount -= 1;
}
return 0;
}