[Win32utils-devel] Bug in new_work_item

win32utils-devel at rubyforge.org win32utils-devel at rubyforge.org
Sun Aug 1 01:34:57 EDT 2004


> Hi all,
> 
...
> I've checked in some updated code, so take a look at
> what I've got in CVS and see if you can duplicate the
> problem and, if possible, figure out why it's
> segfaulting. :)
> 
> Thanks.
> 
> Dan
> 
> PS - I'll submit a bug report for the Tracker
> 
Hi, all

I attached fixed taskscheduler.c

Regards,

Park Heesob
-------------- next part --------------
/****************************************************************************
 * taskscheduler.c - source for the win32-taskscheduler package
 *
 * Author: Daniel J. Berger
 ****************************************************************************/
#include "ruby.h"
#include <windows.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <objidl.h>
#include <wchar.h>
#include <stdio.h>
#include "taskscheduler.h"

static VALUE cTaskSchedulerError;
static char error[ERROR_BUFFER];

static VALUE ts_allocate(VALUE klass){
   TSStruct* ptr = (TSStruct*)malloc(sizeof(TSStruct));
   return Data_Wrap_Struct(klass,0,ts_free,ptr);
}

static VALUE ts_init(VALUE self)
{
   ITaskScheduler *pITS;
   HRESULT hr = S_OK;
   TSStruct* ptr;
   Data_Get_Struct(self,TSStruct,ptr);
   ptr->pITS = NULL;
   ptr->pITask = NULL;
   
   /////////////////////////////////////////////////////////////////
   // 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();
         rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
      }
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
   ptr->pITS = pITS;
   ptr->pITask = NULL;
   return self;
}

static VALUE ts_enum(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    IEnumWorkItems *pIEnum;
    LPWSTR *lpwszNames;
    VALUE rbEnum;
    char dest[NAME_MAX];
    DWORD dwFetchedTasks = 0;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    /////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::Enum to get an enumeration object.
    /////////////////////////////////////////////////////////////////
    hr = ptr->pITS->Enum(&pIEnum);

    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    rbEnum = rb_ary_new();

    /////////////////////////////////////////////////////////////////
    // Call IEnumWorkItems::Next to retrieve tasks. Note that
    // this example tries to retrieve five tasks for each call.
    /////////////////////////////////////////////////////////////////
    while (SUCCEEDED(pIEnum->Next(TASKS_TO_RETRIEVE,
                                &lpwszNames,
                                &dwFetchedTasks))
                  && (dwFetchedTasks != 0))
    {
        ///////////////////////////////////////////////////////////////
        // Process each task. Note that this example prints the
        // name of each task to the screen.
        //////////////////////////////////////////////////////////////
        while (dwFetchedTasks)
        {
            WideCharToMultiByte(
               CP_ACP,
               0,
               lpwszNames[--dwFetchedTasks],
               -1,
               dest,
               NAME_MAX,
               NULL,
               NULL
            );
            rb_ary_push(rbEnum,rb_str_new2(dest));
            CoTaskMemFree(lpwszNames[dwFetchedTasks]);
        }
        CoTaskMemFree(lpwszNames);
    }

    pIEnum->Release();

    return rbEnum;
}

static VALUE ts_activate(VALUE self,VALUE job)
{
    TSStruct* ptr;
    HRESULT hr;
    wchar_t cwszTaskName[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    
    MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(job),
      RSTRING(job)->len+1,
      cwszTaskName,
      NAME_MAX
    );

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::Activate Task
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITS->Activate(cwszTaskName,IID_ITask,
                      (IUnknown**) &(ptr->pITask));
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_delete(VALUE self,VALUE job)
{
    TSStruct* ptr;
    HRESULT hr;
    wchar_t cwszTaskName[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    
    MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(job),
      RSTRING(job)->len+1,
      cwszTaskName,
      NAME_MAX
    );

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::Delete
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITS->Delete(cwszTaskName);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_run(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITask::Run to start execution of Task
    ///////////////////////////////////////////////////////////////////

    hr = ptr->pITask->Run();
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_save(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    IPersistFile *pIPersistFile;
    LPOLESTR ppszFileName;
    
    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    /////////////////////////////////////////////////////////////////
    // Call IUnknown::QueryInterface to get a pointer to
    // IPersistFile and IPersistFile::Save to save
    // the new task to disk.
    /////////////////////////////////////////////////////////////////

    hr = ptr->pITask->QueryInterface(IID_IPersistFile,
                              (void **)&pIPersistFile);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITask::Save
    ///////////////////////////////////////////////////////////////////
    hr = pIPersistFile->Save(NULL,TRUE);
    if (FAILED(hr))
    {
		strcpy(error,ErrorDescription(GetLastError()));
        pIPersistFile->Release();
        rb_raise(cTaskSchedulerError,error);
    }    
    pIPersistFile->Release();

   /////////////////////////////////////////////////////////////////
   // Call CoInitialize to initialize the COM library and then
   // CoCreateInstance to get the Task Scheduler object.
   // Added by phasis68 
   /////////////////////////////////////////////////////////////////
   CoUninitialize();
   hr = CoInitialize(NULL);
   if(SUCCEEDED(hr)){
      hr = CoCreateInstance(
         CLSID_CTaskScheduler,
         NULL,
         CLSCTX_INPROC_SERVER,
         IID_ITaskScheduler,
         (void **) &(ptr->pITS)
      );
           
      if(FAILED(hr)){
         CoUninitialize();
         rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
      }
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
    
    ptr->pITask->Release();
    
    return Qtrue;
}

static VALUE ts_terminate(VALUE self,VALUE job)
{
    TSStruct* ptr;
    HRESULT hr;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITask::Terminate to terminate execution of Task
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->Terminate();
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_set_target_computer(VALUE self,VALUE host)
{
    TSStruct* ptr;
    HRESULT hr;
    wchar_t cwszHostName[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(host),
      RSTRING(host)->len+1,
      cwszHostName,
      NAME_MAX
    );

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetTargetComputer
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITS->SetTargetComputer(cwszHostName);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_set_account_information(VALUE self,VALUE usr,VALUE pwd)
{
   TSStruct* ptr;
   HRESULT hr;
   wchar_t cwszUsername[NAME_MAX];
   wchar_t cwszPassword[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   if((usr==Qnil || RSTRING(usr)->len==0)
      && (pwd==Qnil || RSTRING(pwd)->len==0)){
      ///////////////////////////////////////////////////////////////////
      // Call ITaskScheduler::SetAccountInformation
      ///////////////////////////////////////////////////////////////////
      hr = ptr->pITask->SetAccountInformation(L"",NULL);
   }
   else{
      MultiByteToWideChar(CP_ACP,0,StringValuePtr(usr),
         RSTRING(usr)->len+1,cwszUsername,NAME_MAX);
      MultiByteToWideChar(CP_ACP,0,StringValuePtr(pwd),
         RSTRING(pwd)->len+1,cwszPassword,NAME_MAX);

      ///////////////////////////////////////////////////////////////////
      // Call ITaskScheduler::SetAccountInformation
      ///////////////////////////////////////////////////////////////////
      hr = ptr->pITask->SetAccountInformation(cwszUsername,cwszPassword);
   }
	switch(hr) {
		case S_OK : return Qtrue;
		case E_ACCESSDENIED : return INT2NUM(0);
		case E_INVALIDARG : return INT2NUM(-1);
		case E_OUTOFMEMORY : return INT2NUM(-2);
		case SCHED_E_NO_SECURITY_SERVICES : return INT2NUM(-3);
#ifdef SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
		case SCHED_E_UNSUPPORTED_ACCOUNT_OPTION : return INT2NUM(-4);
#endif
#ifdef SCHED_E_ACCOUNT_INFORMATION_NOT_SET
		case SCHED_E_ACCOUNT_INFORMATION_NOT_SET  : return INT2NUM(-5);
#endif
		default : return INT2NUM(-6);
	}
}

static VALUE ts_get_account_information(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   LPWSTR lpcwszUsername;
   char user[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"null pointer error (account_information");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetAccountInformation
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetAccountInformation(&lpcwszUsername);
	if(SUCCEEDED(hr) && hr != SCHED_E_NO_SECURITY_SERVICES){
      WideCharToMultiByte(
         CP_ACP,
         0,
         lpcwszUsername,
         -1,
         user,
         NAME_MAX,
         NULL,
         NULL
      );
      CoTaskMemFree(lpcwszUsername);
      return rb_str_new2(user);
	}
   else{
		strcpy(error,ErrorDescription(GetLastError()));
      CoTaskMemFree(lpcwszUsername);
      rb_raise(cTaskSchedulerError,error);
	}
}

static VALUE ts_set_application_name(VALUE self,VALUE app)
{
    TSStruct* ptr;
    HRESULT hr;
    wchar_t cwszAppname[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    MultiByteToWideChar(CP_ACP,0,StringValuePtr(app),RSTRING(app)->len+1,cwszAppname,NAME_MAX);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetApplicationName
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->SetApplicationName(cwszAppname);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;

}

static VALUE ts_get_application_name(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    LPWSTR lpcwszAppname;
    char app[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::GetApplicationName
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->GetApplicationName(&lpcwszAppname);
	if(SUCCEEDED(hr))
	{
        WideCharToMultiByte(CP_ACP, 0, lpcwszAppname, -1, app, NAME_MAX, NULL, NULL );
        CoTaskMemFree(lpcwszAppname);
        return rb_str_new2(app);
    } else {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
}

static VALUE ts_set_parameters(VALUE self,VALUE param)
{
    TSStruct* ptr;
    HRESULT hr;
    wchar_t cwszParameters[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    MultiByteToWideChar(CP_ACP,0,StringValuePtr(param),
      RSTRING(param)->len+1,cwszParameters,NAME_MAX);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetParameters
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->SetParameters(cwszParameters);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;

}

static VALUE ts_get_parameters(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   LPWSTR lpcwszParameters;
   char param[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetParameters
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetParameters(&lpcwszParameters);
	if(SUCCEEDED(hr))
	{
      WideCharToMultiByte(CP_ACP, 0, lpcwszParameters, -1, param,
         NAME_MAX, NULL, NULL );
      CoTaskMemFree(lpcwszParameters);
      return rb_str_new2(param);
    }
    else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
}

static VALUE ts_set_working_directory(VALUE self, VALUE direc)
{
   TSStruct* ptr;
   HRESULT hr;
   wchar_t cwszDirectory[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(direc),
      RSTRING(direc)->len+1,
      cwszDirectory,
      NAME_MAX
   );

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::SetWorkingDirectory
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->SetWorkingDirectory(cwszDirectory);
   if(FAILED(hr)){
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
   return Qtrue;
}

static VALUE ts_get_working_directory(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   LPWSTR lpcwszDirectory;
   char dir[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetWorkingDirectory
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetWorkingDirectory(&lpcwszDirectory);
	if(SUCCEEDED(hr)){
      WideCharToMultiByte(
         CP_ACP,
         0,
         lpcwszDirectory,
         -1,
         dir,
         NAME_MAX,
         NULL,
         NULL
      );
      CoTaskMemFree(lpcwszDirectory);
      return rb_str_new2(dir);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_set_priority(VALUE self,VALUE pri)
{
    TSStruct* ptr;
    HRESULT hr;
    DWORD dwPriority;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    dwPriority = NUM2UINT(pri);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetPriority
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->SetPriority(dwPriority);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;

}

static VALUE ts_get_priority(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   DWORD dwPriority;

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL){
      rb_raise(cTaskSchedulerError,"null pointer error (priority)");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetPriority
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetPriority(&dwPriority);
	if(SUCCEEDED(hr)){
      if(dwPriority & IDLE_PRIORITY_CLASS){
         return rb_str_new2("idle");
      }
      if(dwPriority & NORMAL_PRIORITY_CLASS){
         return rb_str_new2("normal");
      }
      if(dwPriority & HIGH_PRIORITY_CLASS){
         return rb_str_new2("high");
      }
      if(dwPriority & REALTIME_PRIORITY_CLASS){
         return rb_str_new2("realtime");
      }
#ifdef BELOW_NORMAL_PRIORITY_CLASS
      if(dwPriority & BELOW_NORMAL_PRIORITY_CLASS){
         return rb_str_new2("below_normal");
      }
#endif
#ifdef ABOVE_NORMAL_PRIORITY_CLASS
      if(dwPriority & ABOVE_NORMAL_PRIORITY_CLASS){
         return rb_str_new2("above_normal");
      }
#endif
      return rb_str_new2("unknown");
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_new_work_item(VALUE self,VALUE job,VALUE trigger)
{
   TSStruct* ptr;
   HRESULT hr;
   wchar_t cwszTaskName[NAME_MAX];
   ITaskTrigger *pITaskTrigger;
   WORD piNewTrigger;
   TASK_TRIGGER pTrigger;
   VALUE i, htmp;

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL) {
      rb_raise(cTaskSchedulerError,"null pointer error (new_work_item)");
   }

   if(ptr->pITask != NULL) {
      ptr->pITask->Release();
      ptr->pITask = NULL;
   }

   MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(job),
      RSTRING(job)->len+1,
      cwszTaskName,
      NAME_MAX
   );

   /////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::NewWorkItem to create new task.
   /////////////////////////////////////////////////////////////////
   hr = ptr->pITS->NewWorkItem(
      cwszTaskName,                 // Name of task
      CLSID_CTask,                  // Class identifier
      IID_ITask,                    // Interface identifier
      (IUnknown**)&(ptr->pITask)    // Address of task interface
   );
  
   if(FAILED(hr)){
      ptr->pITask = NULL;    // added by phasis68 for ts_free prevent
      rb_raise(cTaskSchedulerError,"NewWorkItem() function failed");
   }

   if(TYPE(trigger)==T_HASH) {
      ///////////////////////////////////////////////////////////////////
      // Call ITask::CreateTrigger to create new trigger.
      ///////////////////////////////////////////////////////////////////

      hr = ptr->pITask->CreateTrigger(&piNewTrigger,&pITaskTrigger);
      if (FAILED(hr))
      {
         rb_raise(cTaskSchedulerError,"CreateTrigger() failed");
      }

      //////////////////////////////////////////////////////
      // Define TASK_TRIGGER structure. Note that wBeginDay,
      // wBeginMonth, and wBeginYear must be set to a valid
      // day, month, and year respectively.
      //////////////////////////////////////////////////////

      ZeroMemory(&pTrigger, sizeof (TASK_TRIGGER));
      pTrigger.cbTriggerSize = sizeof (TASK_TRIGGER);

      if((i=rb_hash_aref(trigger, rb_str_new2("start_year")))!=Qnil)
         pTrigger.wBeginYear = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("start_month")))!=Qnil)
         pTrigger.wBeginMonth = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("start_day")))!=Qnil)
         pTrigger.wBeginDay = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("end_year")))!=Qnil)
         pTrigger.wEndYear = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("end_month")))!=Qnil)
         pTrigger.wEndMonth = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("end_day")))!=Qnil)
         pTrigger.wEndDay = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("start_hour")))!=Qnil)
         pTrigger.wStartHour = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("start_minute")))!=Qnil)
         pTrigger.wStartMinute = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("minutes_duration")))!=Qnil)
         pTrigger.MinutesDuration = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("minutes_interval")))!=Qnil)
         pTrigger.MinutesInterval = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("random_minutes_interval")))!=Qnil)
         pTrigger.wRandomMinutesInterval = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("flags")))!=Qnil)
         pTrigger.rgFlags = NUM2INT(i);
      if((i=rb_hash_aref(trigger, rb_str_new2("trigger_type")))!=Qnil)
         pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
        htmp =rb_hash_aref(trigger, rb_str_new2("type"));
      if(TYPE(htmp)!=T_HASH) htmp = Qnil;

      switch(pTrigger.TriggerType) {
         case TASK_TIME_TRIGGER_DAILY:
            if(htmp!=Qnil){
               if((i=rb_hash_aref(htmp, rb_str_new2("days_interval")))!=Qnil)
                  pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
            }
            break;
         case TASK_TIME_TRIGGER_WEEKLY:
            if(htmp!=Qnil) {
               if((i=rb_hash_aref(htmp, rb_str_new2("weeks_interval")))!=Qnil)
                  pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
               if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                  pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
            }
            break;
         case TASK_TIME_TRIGGER_MONTHLYDATE:
            if(htmp!=Qnil){
               if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                  pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
               if((i=rb_hash_aref(htmp, rb_str_new2("days")))!=Qnil)
                  pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
            }
            break;
         case TASK_TIME_TRIGGER_MONTHLYDOW:
            if(htmp!=Qnil) {
               if((i=rb_hash_aref(htmp, rb_str_new2("weeks")))!=Qnil)
                  pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
               if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                  pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
               if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                  pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
            }
            break;
        }

      ///////////////////////////////////////////////////////////////////
      // Call ITaskTrigger::SetTrigger to set trigger criteria.
      ///////////////////////////////////////////////////////////////////
      hr = pITaskTrigger->SetTrigger (&pTrigger);
      if (FAILED(hr))
      {
         //rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
         rb_raise(cTaskSchedulerError,"SetTrigger() failed");
      }
      pITaskTrigger->Release();
      return Qtrue;
   }
   return Qtrue;
}

static VALUE ts_get_trigger_count(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerCount;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::GetTriggerCount
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->GetTriggerCount(&TriggerCount);
	if(SUCCEEDED(hr))
	{
        return UINT2NUM(TriggerCount);
    } else {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
}

static VALUE ts_get_trigger_string(VALUE self,VALUE index)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerIndex;
    LPWSTR ppwszTrigger;
    char str[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    TriggerIndex = NUM2INT(index);

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetTriggerString
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetTriggerString(TriggerIndex,&ppwszTrigger);
   
	if(SUCCEEDED(hr)){
      WideCharToMultiByte(CP_ACP,0,ppwszTrigger,-1,str,NAME_MAX,NULL,NULL);
	   CoTaskMemFree(ppwszTrigger);
      return rb_str_new2(str);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_delete_trigger(VALUE self,VALUE index)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerIndex;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    TriggerIndex = NUM2INT(index);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::DeleteTrigger
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->DeleteTrigger(TriggerIndex);
	if(FAILED(hr)) {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;
}

static VALUE ts_get_trigger(VALUE self,VALUE index)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerIndex;
    VALUE trigger,htmp;
	ITaskTrigger *pITaskTrigger;
	TASK_TRIGGER pTrigger;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    TriggerIndex = NUM2INT(index);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::GetTrigger
    ///////////////////////////////////////////////////////////////////
	hr = ptr->pITask->GetTrigger(TriggerIndex,&pITaskTrigger);
	if(FAILED(hr))
	{
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
	ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));
	pTrigger.cbTriggerSize = sizeof (TASK_TRIGGER);

	hr = pITaskTrigger->GetTrigger(&pTrigger);
	if(FAILED(hr)) {
		strcpy(error,ErrorDescription(GetLastError()));
        pITaskTrigger->Release();
        rb_raise(cTaskSchedulerError,error);
	}
    trigger = rb_hash_new();
    rb_hash_aset(trigger, rb_str_new2("start_year"), INT2NUM(pTrigger.wBeginYear));
    rb_hash_aset(trigger, rb_str_new2("start_month"), INT2NUM(pTrigger.wBeginMonth));
    rb_hash_aset(trigger, rb_str_new2("start_day"), INT2NUM(pTrigger.wBeginDay));
    rb_hash_aset(trigger, rb_str_new2("end_year"), INT2NUM(pTrigger.wEndYear));
    rb_hash_aset(trigger, rb_str_new2("end_month"), INT2NUM(pTrigger.wEndMonth));
    rb_hash_aset(trigger, rb_str_new2("end_day"), INT2NUM(pTrigger.wEndDay));
    rb_hash_aset(trigger, rb_str_new2("start_hour"), INT2NUM(pTrigger.wStartHour));
    rb_hash_aset(trigger, rb_str_new2("start_minute"), INT2NUM(pTrigger.wStartMinute));
    rb_hash_aset(trigger, rb_str_new2("minutes_duration"), INT2NUM(pTrigger.MinutesDuration));
    rb_hash_aset(trigger, rb_str_new2("minutes_interval"), INT2NUM(pTrigger.MinutesInterval));
    rb_hash_aset(trigger, rb_str_new2("trigger_type"), INT2NUM(pTrigger.TriggerType));
    rb_hash_aset(trigger, rb_str_new2("random_minutes_interval"), INT2NUM(pTrigger.wRandomMinutesInterval));
    rb_hash_aset(trigger, rb_str_new2("flags"), INT2NUM(pTrigger.rgFlags));

	switch(pTrigger.TriggerType) {

        case TASK_TIME_TRIGGER_DAILY             :
				htmp=rb_hash_new();
				rb_hash_aset(htmp, rb_str_new2("days_interval"), INT2NUM(pTrigger.Type.Daily.DaysInterval));
				rb_hash_aset(trigger, rb_str_new2("type"), htmp);
				break;
	    case TASK_TIME_TRIGGER_WEEKLY            :
				htmp=rb_hash_new();
				rb_hash_aset(htmp, rb_str_new2("weeks_interval"), INT2NUM(pTrigger.Type.Weekly.WeeksInterval));
				rb_hash_aset(htmp, rb_str_new2("days_of_week"), INT2NUM(pTrigger.Type.Weekly.rgfDaysOfTheWeek));
				rb_hash_aset(trigger, rb_str_new2("type"), htmp);
				break;
	    case TASK_TIME_TRIGGER_MONTHLYDATE       :
				htmp=rb_hash_new();
				rb_hash_aset(htmp, rb_str_new2("days"), INT2NUM(bitFieldToHumanDays(pTrigger.Type.MonthlyDate.rgfDays)));
				rb_hash_aset(htmp, rb_str_new2("months"), INT2NUM(pTrigger.Type.MonthlyDate.rgfMonths));
				rb_hash_aset(trigger, rb_str_new2("type"), htmp);
				break;
	    case TASK_TIME_TRIGGER_MONTHLYDOW        :
				htmp=rb_hash_new();
				rb_hash_aset(htmp, rb_str_new2("weeks"), INT2NUM(bitFieldToHumanDays(pTrigger.Type.MonthlyDOW.wWhichWeek)));
				rb_hash_aset(htmp, rb_str_new2("days_of_week"), INT2NUM(pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek));
				rb_hash_aset(htmp, rb_str_new2("months"), INT2NUM(pTrigger.Type.MonthlyDOW.rgfMonths));
				rb_hash_aset(trigger, rb_str_new2("type"), htmp);
				break;
	}

	pITaskTrigger->Release();
    return trigger;
}

static VALUE ts_set_trigger(VALUE self,VALUE index,VALUE trigger)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerIndex;
    ITaskTrigger *pITaskTrigger;
    TASK_TRIGGER pTrigger;
    VALUE i;
    VALUE htmp;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    TriggerIndex = NUM2INT(index);

    hr=ptr->pITask->GetTrigger(TriggerIndex,&pITaskTrigger);
	if(FAILED(hr)) {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));

    if(TYPE(trigger)==T_HASH) {
        //////////////////////////////////////////////////////
        // Define TASK_TRIGGER structure. Note that wBeginDay,
        // wBeginMonth, and wBeginYear must be set to a valid
        // day, month, and year respectively.
        //////////////////////////////////////////////////////

        ZeroMemory(&pTrigger, sizeof (TASK_TRIGGER));
        pTrigger.cbTriggerSize = sizeof (TASK_TRIGGER);

        if((i=rb_hash_aref(trigger, rb_str_new2("start_year")))!=Qnil)
         pTrigger.wBeginYear = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_month")))!=Qnil)
         pTrigger.wBeginMonth = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_day")))!=Qnil)
         pTrigger.wBeginDay = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_year")))!=Qnil)
         pTrigger.wEndYear = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_month")))!=Qnil)
         pTrigger.wEndMonth = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_day")))!=Qnil)
         pTrigger.wEndDay = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_hour")))!=Qnil)
         pTrigger.wStartHour = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_minute")))!=Qnil)
         pTrigger.wStartMinute = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("minutes_duration")))!=Qnil)
         pTrigger.MinutesDuration = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("minutes_interval")))!=Qnil)
         pTrigger.MinutesInterval = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("random_minutes_interval")))!=Qnil)
         pTrigger.wRandomMinutesInterval = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("flags")))!=Qnil)
         pTrigger.rgFlags = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("trigger_type")))!=Qnil)
         pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
        htmp =rb_hash_aref(trigger, rb_str_new2("type"));
        if(TYPE(htmp)!=T_HASH) htmp = Qnil;

        switch(pTrigger.TriggerType) {
            case TASK_TIME_TRIGGER_DAILY:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_interval")))!=Qnil)
                     pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
                }
                break;
            case TASK_TIME_TRIGGER_WEEKLY:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("weeks_interval")))!=Qnil)
                     pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                     pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
                }
                break;
            case TASK_TIME_TRIGGER_MONTHLYDATE:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                     pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days")))!=Qnil)
                     pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
                }
                break;
            case TASK_TIME_TRIGGER_MONTHLYDOW:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("weeks")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
                }
                break;
        }

        ///////////////////////////////////////////////////////////////////
        // Call ITaskTrigger::SetTrigger to set trigger criteria.
        ///////////////////////////////////////////////////////////////////
        hr = pITaskTrigger->SetTrigger (&pTrigger);
        if (FAILED(hr))
        {
            rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
        }
        pITaskTrigger->Release();
        return Qtrue;
    }
    return Qtrue;
}

static VALUE ts_create_trigger(VALUE self,VALUE trigger)
{
    TSStruct* ptr;
    HRESULT hr;
    WORD TriggerIndex;
    ITaskTrigger *pITaskTrigger;
    TASK_TRIGGER pTrigger;
    VALUE i;
    VALUE htmp;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    hr=ptr->pITask->CreateTrigger(&TriggerIndex,&pITaskTrigger);
	if(FAILED(hr)) {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    ZeroMemory(&pTrigger, sizeof(TASK_TRIGGER));

    if(TYPE(trigger)==T_HASH) {
        //////////////////////////////////////////////////////
        // Define TASK_TRIGGER structure. Note that wBeginDay,
        // wBeginMonth, and wBeginYear must be set to a valid
        // day, month, and year respectively.
        //////////////////////////////////////////////////////

        ZeroMemory(&pTrigger, sizeof (TASK_TRIGGER));
        pTrigger.cbTriggerSize = sizeof (TASK_TRIGGER);

        if((i=rb_hash_aref(trigger, rb_str_new2("start_year")))!=Qnil)
         pTrigger.wBeginYear = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_month")))!=Qnil)
         pTrigger.wBeginMonth = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_day")))!=Qnil)
         pTrigger.wBeginDay = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_year")))!=Qnil)
         pTrigger.wEndYear = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_month")))!=Qnil)
         pTrigger.wEndMonth = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("end_day")))!=Qnil)
         pTrigger.wEndDay = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_hour")))!=Qnil)
         pTrigger.wStartHour = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("start_minute")))!=Qnil)
         pTrigger.wStartMinute = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("minutes_duration")))!=Qnil)
         pTrigger.MinutesDuration = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("minutes_interval")))!=Qnil)
         pTrigger.MinutesInterval = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("random_minutes_interval")))!=Qnil)
         pTrigger.wRandomMinutesInterval = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("flags")))!=Qnil)
         pTrigger.rgFlags = NUM2INT(i);
        if((i=rb_hash_aref(trigger, rb_str_new2("trigger_type")))!=Qnil)
         pTrigger.TriggerType = (TASK_TRIGGER_TYPE)NUM2INT(i);
        htmp =rb_hash_aref(trigger, rb_str_new2("type"));
        if(TYPE(htmp)!=T_HASH) htmp = Qnil;

        switch(pTrigger.TriggerType) {
            case TASK_TIME_TRIGGER_DAILY:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_interval")))!=Qnil)
                     pTrigger.Type.Daily.DaysInterval = NUM2INT(i);
                }
                break;
            case TASK_TIME_TRIGGER_WEEKLY:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("weeks_interval")))!=Qnil)
                     pTrigger.Type.Weekly.WeeksInterval = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                     pTrigger.Type.Weekly.rgfDaysOfTheWeek = NUM2INT(i);
                }
                break;
            case TASK_TIME_TRIGGER_MONTHLYDATE:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                     pTrigger.Type.MonthlyDate.rgfMonths = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days")))!=Qnil)
                     pTrigger.Type.MonthlyDate.rgfDays = humanDaysToBitField(NUM2INT(i));
                }
                break;
            case TASK_TIME_TRIGGER_MONTHLYDOW:
                if(htmp!=Qnil) {
                    if((i=rb_hash_aref(htmp, rb_str_new2("weeks")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.wWhichWeek = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("days_of_week")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.rgfDaysOfTheWeek = NUM2INT(i);
                    if((i=rb_hash_aref(htmp, rb_str_new2("months")))!=Qnil)
                     pTrigger.Type.MonthlyDOW.rgfMonths = NUM2INT(i);
                }
                break;
        }

        ///////////////////////////////////////////////////////////////////
        // Call ITaskTrigger::SetTrigger to set trigger criteria.
        ///////////////////////////////////////////////////////////////////
        hr = pITaskTrigger->SetTrigger (&pTrigger);
        if (FAILED(hr))
        {
            rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
        }
        pITaskTrigger->Release();
        return Qtrue;
    }
    return Qtrue;
}

static VALUE ts_set_flags(VALUE self,VALUE flags)
{
    TSStruct* ptr;
    HRESULT hr;
    DWORD dwFlags;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    dwFlags = NUM2UINT(flags);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetFlags
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->SetFlags(dwFlags);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;

}

static VALUE ts_get_flags(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    DWORD dwFlags;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::GetFlags
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->GetFlags(&dwFlags);
	if(SUCCEEDED(hr))
	{
        return UINT2NUM(dwFlags);
    } else {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
}

static VALUE ts_get_status(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   HRESULT st;

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetStatus
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetStatus(&st);
	if(SUCCEEDED(hr)){
      switch((DWORD)st){
         case SCHED_S_TASK_READY:
            return rb_str_new2("ready");
         case SCHED_S_TASK_RUNNING:
            return rb_str_new2("running");
         case SCHED_S_TASK_NOT_SCHEDULED:
            return rb_str_new2("not scheduled");
         default:
            return rb_str_new2("unknown");
      };
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_get_exit_code(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   DWORD dwCode;

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetExitCode
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetExitCode(&dwCode);
	if(SUCCEEDED(hr)){
      return UINT2NUM(dwCode);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_set_comment(VALUE self,VALUE com)
{
   TSStruct* ptr;
   HRESULT hr;
   wchar_t cwszComment[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(com),
      RSTRING(com)->len+1,
      cwszComment,
      NAME_MAX
   );

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::SetComment
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->SetComment(cwszComment);
   if(FAILED(hr)){
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
   return Qtrue;
}

static VALUE ts_get_comment(VALUE self)
{
    TSStruct* ptr;
    HRESULT hr;
    LPWSTR lpcwszComment;
    char com[NAME_MAX];

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::GetComment
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->GetComment(&lpcwszComment);
	if(SUCCEEDED(hr))
	{
        WideCharToMultiByte(CP_ACP, 0, lpcwszComment, -1, com, NAME_MAX, NULL, NULL );
        CoTaskMemFree(lpcwszComment);
        return rb_str_new2(com);
    } else {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
}

static VALUE ts_set_creator(VALUE self,VALUE crt){
   TSStruct* ptr;
   HRESULT hr;
   wchar_t cwszCreator[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   MultiByteToWideChar(
      CP_ACP,
      0,
      StringValuePtr(crt),
      RSTRING(crt)->len+1,
      cwszCreator,
      NAME_MAX
   );

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::SetCreator
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->SetCreator(cwszCreator);
   if (FAILED(hr)){
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
   return Qtrue;
}

static VALUE ts_get_creator(VALUE self){
   TSStruct* ptr;
   HRESULT hr;
   LPWSTR lpcwszCreator;
   char crt[NAME_MAX];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetCreator
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetCreator(&lpcwszCreator);
	if(SUCCEEDED(hr)){
      WideCharToMultiByte(CP_ACP,0,lpcwszCreator,-1,crt, NAME_MAX, NULL, NULL);
      CoTaskMemFree(lpcwszCreator);
      return rb_str_new2(crt);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_get_next_run_time(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   SYSTEMTIME nextRun;
   VALUE argv[7];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"null pointer error (next_run_time)");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetNextRunTime
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetNextRunTime(&nextRun);
	if(SUCCEEDED(hr)){
      argv[0] = INT2NUM(nextRun.wYear);
      argv[1] = INT2NUM(nextRun.wMonth);
      argv[2] = INT2NUM(nextRun.wDay);
      argv[3] = INT2NUM(nextRun.wHour);
      argv[4] = INT2NUM(nextRun.wMinute);
      argv[5] = INT2NUM(nextRun.wSecond);
      argv[6] = INT2NUM(nextRun.wMilliseconds*1000);
      return rb_funcall2(rb_cTime, rb_intern("local"), 7, argv);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_get_most_recent_run_time(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   SYSTEMTIME lastRun;
   VALUE argv[7];

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"fatal error: null pointer");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetMostRecentRunTime
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetMostRecentRunTime(&lastRun);
   if(SCHED_S_TASK_HAS_NOT_RUN == hr){
      return Qnil;
   }
   
	if(SUCCEEDED(hr)){
      argv[0] = INT2NUM(lastRun.wYear);
      argv[1] = INT2NUM(lastRun.wMonth);
      argv[2] = INT2NUM(lastRun.wDay);
      argv[3] = INT2NUM(lastRun.wHour);
      argv[4] = INT2NUM(lastRun.wMinute);
      argv[5] = INT2NUM(lastRun.wSecond);
      argv[6] = INT2NUM(lastRun.wMilliseconds*1000);
      return rb_funcall2(rb_cTime, rb_intern("local"), 7, argv);
   }
   else{     
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

static VALUE ts_set_max_run_time(VALUE self,VALUE maxruntime)
{
    TSStruct* ptr;
    HRESULT hr;
    DWORD maxRunTimeMilliSeconds;

    Data_Get_Struct(self,TSStruct,ptr);

    if(ptr->pITS==NULL || ptr->pITask==NULL) {
        rb_raise(cTaskSchedulerError,"fatal error: null pointer");
    }
    maxRunTimeMilliSeconds = NUM2UINT(maxruntime);

    ///////////////////////////////////////////////////////////////////
    // Call ITaskScheduler::SetMaxRunTime
    ///////////////////////////////////////////////////////////////////
    hr = ptr->pITask->SetMaxRunTime(maxRunTimeMilliSeconds);
    if (FAILED(hr))
    {
        rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
    }
    return Qtrue;

}

static VALUE ts_get_max_run_time(VALUE self)
{
   TSStruct* ptr;
   HRESULT hr;
   DWORD maxRunTimeMilliSeconds;

   Data_Get_Struct(self,TSStruct,ptr);

   if(ptr->pITS==NULL || ptr->pITask==NULL) {
      rb_raise(cTaskSchedulerError,"null pointer error (max_run_time)");
   }

   ///////////////////////////////////////////////////////////////////
   // Call ITaskScheduler::GetMaxRunTime
   ///////////////////////////////////////////////////////////////////
   hr = ptr->pITask->GetMaxRunTime(&maxRunTimeMilliSeconds);
	if(SUCCEEDED(hr)){
      return UINT2NUM(maxRunTimeMilliSeconds);
   }
   else{
      rb_raise(cTaskSchedulerError,ErrorDescription(GetLastError()));
   }
}

// The C++ code requires explicit function casting via 'VALUEFUNC' 
void Init_taskscheduler()
{
   VALUE mWin32, cTaskScheduler;;

   // Modules and classes
   mWin32 = rb_define_module("Win32");
   cTaskScheduler = rb_define_class_under(mWin32, "TaskScheduler", rb_cObject);
   cTaskSchedulerError = rb_define_class_under(mWin32,"TaskSchedulerError",
      rb_eStandardError);

   // Taskscheduler class and instance methods
   rb_define_alloc_func(cTaskScheduler,ts_allocate);
   rb_define_method(cTaskScheduler,"initialize",VALUEFUNC(ts_init),0);      
   rb_define_method(cTaskScheduler,"enum",VALUEFUNC(ts_enum),0);
   rb_define_method(cTaskScheduler,"activate",VALUEFUNC(ts_activate),1);
   rb_define_method(cTaskScheduler,"delete",VALUEFUNC(ts_delete),1);
   rb_define_method(cTaskScheduler,"run",VALUEFUNC(ts_run),0);
   rb_define_method(cTaskScheduler,"save",VALUEFUNC(ts_save),0);
   rb_define_method(cTaskScheduler,"terminate",VALUEFUNC(ts_terminate),0);
   
   rb_define_method(cTaskScheduler,"machine=",
      VALUEFUNC(ts_set_target_computer),1);
    
   rb_define_method(cTaskScheduler,"set_account_information",
      VALUEFUNC(ts_set_account_information),2);
   rb_define_method(cTaskScheduler,"account_information",
      VALUEFUNC(ts_get_account_information),0);
    
   rb_define_method(cTaskScheduler,"application_name",
    	VALUEFUNC(ts_get_application_name),0);
   rb_define_method(cTaskScheduler,"application_name=",
      VALUEFUNC(ts_set_application_name),1);

    rb_define_method(cTaskScheduler,"parameters",
    	VALUEFUNC(ts_get_parameters),0);   
    rb_define_method(cTaskScheduler,"parameters=",
    	VALUEFUNC(ts_set_parameters),1);
   	
    rb_define_method(cTaskScheduler,"working_directory",
    	VALUEFUNC(ts_get_working_directory),0);
    rb_define_method(cTaskScheduler,"working_directory=",
    	VALUEFUNC(ts_set_working_directory),1);

    rb_define_method(cTaskScheduler,"priority",
    	VALUEFUNC(ts_get_priority),0);  	
    rb_define_method(cTaskScheduler,"priority=",
    	VALUEFUNC(ts_set_priority),1);
   	
    rb_define_method(cTaskScheduler,"new_work_item",
      VALUEFUNC(ts_new_work_item),2);
    
    // Trigger related methods	
    rb_define_method(cTaskScheduler,"trigger_count",
    	VALUEFUNC(ts_get_trigger_count),0);    	
    rb_define_method(cTaskScheduler,"trigger_string",
    	VALUEFUNC(ts_get_trigger_string),1);   	
    rb_define_method(cTaskScheduler,"delete_trigger",
    	VALUEFUNC(ts_delete_trigger),1);  	
    rb_define_method(cTaskScheduler,"trigger",
    	VALUEFUNC(ts_get_trigger),1);
    rb_define_method(cTaskScheduler,"trigger=",
     VALUEFUNC(ts_create_trigger),1);    	
    rb_define_method(cTaskScheduler,"create_trigger",
    	VALUEFUNC(ts_create_trigger),1);

    rb_define_method(cTaskScheduler,"flags",
    	VALUEFUNC(ts_get_flags),0);    	
    rb_define_method(cTaskScheduler,"flags=",
    	VALUEFUNC(ts_set_flags),1);
   	
    rb_define_method(cTaskScheduler,"status",
    	VALUEFUNC(ts_get_status),0);
     
    rb_define_method(cTaskScheduler,"exit_code",
    	VALUEFUNC(ts_get_exit_code),0);

    rb_define_method(cTaskScheduler,"comment",
    	VALUEFUNC(ts_get_comment),0);    	
    rb_define_method(cTaskScheduler,"comment=",
    	VALUEFUNC(ts_set_comment),1);

    rb_define_method(cTaskScheduler,"creator",
    	VALUEFUNC(ts_get_creator),0);    	
    rb_define_method(cTaskScheduler,"creator=",
    	VALUEFUNC(ts_set_creator),1);
   	
    rb_define_method(cTaskScheduler,"next_run_time",
    	VALUEFUNC(ts_get_next_run_time),0);
    rb_define_method(cTaskScheduler,"most_recent_run_time",
    	VALUEFUNC(ts_get_most_recent_run_time),0);

    rb_define_method(cTaskScheduler,"max_run_time",
    	VALUEFUNC(ts_get_max_run_time),0);    	
    rb_define_method(cTaskScheduler,"max_run_time=",
    	VALUEFUNC(ts_set_max_run_time),1);

	// Constants
	rb_define_const(cTaskScheduler,"VERSION",
	   rb_str_new2(WIN32_TASKSCHEDULER_VERSION));
	set_constants(cTaskScheduler); 
}



More information about the win32utils-devel mailing list