Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
When you subscribe to job events, you must implement a class that derives from ISchedulerJobEvents. The following C++ example shows a class that implements the ISchedulerJobEvents interface. For an example that shows how to subscribe to the events, see Creating and Submitting a Job.
extern HANDLE g_JobDoneEvent; // Defined in the "Creating and Submitting a Job" topic's C++ example
// Dispath IDs that identify the methods for the ISchedulerJobEvents interface.
#define DISPID_0NJOBSTATE 0x60020000
#define DISPID_ONTASKSTATE 0x60020001
class CJobEventHandler : public ISchedulerJobEvents
{
LONG m_lRefCount;
ITypeInfo* m_pTypeInfo;
public:
// Constructor, Destructor
CJobEventHandler()
{
m_lRefCount = 1;
m_pTypeInfo = NULL;
};
~CJobEventHandler()
{
if (m_pTypeInfo)
{
m_pTypeInfo->Release();
m_pTypeInfo = NULL;
}
};
// IUnknown methods
HRESULT __stdcall QueryInterface(REFIID riid, LPVOID *ppvObj);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
// IDispatch methods
HRESULT __stdcall GetTypeInfoCount(UINT* pCount);
HRESULT __stdcall GetTypeInfo(UINT uiTInfoRequest, LCID lcid, ITypeInfo** ppTInfo);
HRESULT __stdcall GetIDsOfNames(REFIID riid, OLECHAR** ppNames, UINT cNames, LCID lcid, DISPID* pDispId);
HRESULT __stdcall Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr);
// ISchedulerJobEvents methods
void __stdcall OnJobState(VARIANT sender, IJobStateEventArg* args);
void __stdcall OnTaskState(VARIANT sender, ITaskStateEventArg* args);
private:
HRESULT LoadTypeInfo(void);
LPWSTR GetJobStateString(JobState state);
LPWSTR GetTaskStateString(TaskState state);
};
// Strings associated with the job state values.
LPWSTR JobStateStrings[] = {
L"Configuring", L"Submitted", L"Validating",
L"External validation", L"Queued", L"Running",
L"Finishing", L"Finished", L"Failed",
L"Canceled", L"Canceling"
};
// Strings associated with the task state values.
LPWSTR TaskStateStrings[] = {
L"Configuring", L"Submitted", L"Validating",
L"Queued", L"Dispatching", L"Running",
L"Finishing", L"Finished", L"Failed",
L"Canceled", L"Canceling"
};
// IUnknown methods implementation.
HRESULT CJobEventHandler::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
if (riid == __uuidof(IUnknown) ||
riid == __uuidof(IDispatch) ||
riid == __uuidof(ISchedulerJobEvents))
{
*ppvObj = this;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
ULONG CJobEventHandler::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
ULONG CJobEventHandler::Release()
{
ULONG ulCount = InterlockedDecrement(&m_lRefCount);
if(0 == ulCount)
{
delete this;
}
return ulCount;
}
// IDispatch methods implementation.
HRESULT __stdcall CJobEventHandler::GetTypeInfoCount(UINT* pctInfo)
{
HRESULT hr = S_OK;
if (pctInfo == NULL)
return E_INVALIDARG;
hr = LoadTypeInfo();
if (SUCCEEDED(hr))
*pctInfo = 1;
return hr;
}
HRESULT __stdcall CJobEventHandler::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo** ppTInfo)
{
HRESULT hr = S_OK;
if (ppTInfo == NULL)
return E_POINTER;
if(itInfo != 0)
return DISP_E_BADINDEX;
*ppTInfo = NULL;
hr = LoadTypeInfo();
if (SUCCEEDED(hr))
{
m_pTypeInfo->AddRef();
*ppTInfo = m_pTypeInfo;
}
return hr;
}
HRESULT __stdcall CJobEventHandler::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
{
HRESULT hr = S_OK;
hr = LoadTypeInfo();
if (FAILED(hr))
return hr;
return (m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId));
}
// Invoke the event handler methods directly.
HRESULT __stdcall CJobEventHandler::Invoke(DISPID dispId, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
HRESULT hr = S_OK;
ITaskStateEventArg* pTaskStateArgs = NULL;
IJobStateEventArg* pJobStateArgs = NULL;
_variant_t vSender;
_variant_t vArgs;
if (2 != pDispParams->cArgs)
return E_INVALIDARG;
vSender = pDispParams->rgvarg[1]; // IScheduler
vArgs = pDispParams->rgvarg[0]; // Arguments
switch (dispId)
{
case DISPID_ONTASKSTATE :
hr = vArgs.pdispVal->QueryInterface(IID_ITaskStateEventArg, (void**)&pTaskStateArgs);
if (SUCCEEDED(hr))
{
OnTaskState(vSender, pTaskStateArgs);
pTaskStateArgs->Release();
pTaskStateArgs = NULL;
}
break;
case DISPID_0NJOBSTATE :
hr = vArgs.pdispVal->QueryInterface(IID_IJobStateEventArg, (void**)&pJobStateArgs);
if (SUCCEEDED(hr))
{
OnJobState(vSender, pJobStateArgs);
pJobStateArgs->Release();
pJobStateArgs = NULL;
}
break;
default:
hr = DISP_E_BADINDEX; // Bad dispId
}
return hr;
}
HRESULT CJobEventHandler::LoadTypeInfo(void)
{
HRESULT hr;
ITypeLib* pTypeLib = NULL;
if (m_pTypeInfo)
return S_OK;
// Load type library.
hr = LoadRegTypeLib(LIBID_Microsoft_Hpc_Scheduler, 2, 0, LOCALE_USER_DEFAULT, &pTypeLib);
if (SUCCEEDED(hr))
{
// Get type information for interface of the object.
hr = pTypeLib->GetTypeInfoOfGuid(DIID_ISchedulerJobEvents, &m_pTypeInfo);
pTypeLib->Release();
if (FAILED(hr))
m_pTypeInfo = NULL;
}
return hr;
}
// ISchedulerJobEvents implementation
// The SchedulerJob object will call both handler methods. If you do not want
// to handle the event, simply return.
void CJobEventHandler::OnJobState(VARIANT sender, IJobStateEventArg* pargs)
{
HRESULT hr = S_OK;
IScheduler* pScheduler = NULL;
ISchedulerJob* pJob = NULL;
JobState State;
long JobId = 0;
hr = pargs->get_NewState(&State);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pargs->get_JobId(&JobId);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
wprintf(L"\nOnJobState: State for job %d is %s\n", JobId, GetJobStateString(State));
hr = sender.pdispVal->QueryInterface(__uuidof(IScheduler), reinterpret_cast<void **> (&pScheduler));
hr = pScheduler->OpenJob(JobId, &pJob);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
// TODO: Do something with the job.
if (JobState_Finished == State ||
JobState_Failed == State ||
JobState_Canceled == State)
{
SetEvent(g_JobDoneEvent);
}
cleanup:
if (pScheduler)
pScheduler->Release();
if (pJob)
pJob->Release();
}
void CJobEventHandler::OnTaskState(VARIANT sender, ITaskStateEventArg* pargs)
{
HRESULT hr = S_OK;
IScheduler* pScheduler = NULL;
ISchedulerJob* pJob = NULL;
ISchedulerTask* pTask = NULL;
ITaskId* pTaskId = NULL;
TaskState State;
BSTR bstr = NULL;
long JobId = 0;
long JobTaskId = 0;
long InstanceId = 0;
hr = pargs->get_NewState(&State);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pargs->get_JobId(&JobId);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pargs->get_TaskId(&pTaskId);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pTaskId->get_JobTaskId(&JobTaskId);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pTaskId->get_InstanceId(&InstanceId);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
if (InstanceId)
wprintf(L"\nOnTaskState: State for instance %d of task %d is %s\n",
InstanceId, JobTaskId, GetTaskStateString(State));
else
wprintf(L"\nOnTaskState: State for task %d is %s\n", JobTaskId, GetTaskStateString(State));
hr = sender.pdispVal->QueryInterface(__uuidof(IScheduler), reinterpret_cast<void **> (&pScheduler));
// If the task is finished or failed, get the output.
if (TaskState_Finished == State || TaskState_Failed == State)
{
hr = pScheduler->OpenJob(JobId, &pJob);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pJob->OpenTask(pTaskId, &pTask);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
hr = pTask->get_Output(&bstr);
if (FAILED(hr))
{
// Handle error;
goto cleanup;
}
wprintf(L"Output from task:\n%s\n\n", bstr);
}
cleanup:
if (pScheduler)
pScheduler->Release();
if (pJob)
pJob->Release();
if (pTaskId)
pTaskId->Release();
if (bstr)
SysFreeString(bstr);
}
// Returns the string associated with the state value.
LPWSTR CJobEventHandler::GetJobStateString(JobState state)
{
DWORD flag = state;
DWORD bitPosition = 0;
for (bitPosition = 0; flag = flag >> 1; bitPosition++)
;
return JobStateStrings[bitPosition];
}
// Returns the string associated with the state value.
LPWSTR CJobEventHandler::GetTaskStateString(TaskState state)
{
DWORD flag = state;
DWORD bitPosition = 0;
for (bitPosition = 0; flag = flag >> 1; bitPosition++)
;
return TaskStateStrings[bitPosition];
}