Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Windows Mobile – tasker2 runs and stops applications periodically

0.00/5 (No votes)
24 Dec 2011 1  
Tasker2 is a tool to launch or kill applications periodically using windows mobile scheduler. It was born to control the running of agent software on windows mobile at specified times. The problem with the agent software was that it does not open/close connections only on usage times but all the tim

Tasker2 is a tool to launch or kill applications periodically using windows mobile scheduler. It was born to control the running of agent software on windows mobile at specified times. The problem with the agent software was that it does not open/close connections only on usage times but all the time and the device’s battery was drain very fast. We decided to write a helper that would launch and kill the agent to have it running only within a defined time frame.

Background process

We could have written a background process to run external tasks periodically. But the main disadvantage of timers and threads in background processes is that they do not run, if the device is in suspend mode.
To ensure that tasks will be launched also if the device is sleeping, we decided to use the windows mobile scheduler. There are functions inside the notification API to create notifications that will run an application at a specified time. This is what we call a schedule.

The scheduler (notification API)

After a timed schedule has been done by the scheduler, the schedule is removed from the notification database. If you like to have a periodic schedule, you have to ensure that a new schedule is created inside your code.

Pitfalls

During development we found many pitfalls in conjunction with the windows mobile scheduler. This is why I decided to write this post.

The tasks

Tasker2 is a console application without any GUI but it will write a log with all you need to know. Tasker2 supports up to ten tasks. A task is defined using the registry. Every task has an entry for start and stop times, the application to control, an interval for the schedule and a flag for control if a task is only to be run on external power:

REGEDIT4

[HKLM\Software\Tasker\Task1]
"active":DWORD=1
"exe":="\Windows\fexplore.exe"
"arg":="\My Documents"
"start":="1423"
"stop":="1523"
"interval":="2400"
"startOnAConly":DWORD=0;

active: if active is 0, tasker2 will not kill or start the process
exe: name of the process executable to start or kill
arg: arguments to be when launching the executable
start: when to start the executable the next time
stop: when to kill the process the next time
interval: when a start or kill has been executed, tasker2 will create a new schedule using this interval. If the interval is “0010″, the start process will be scheduled for every 10 minutes.
startOnAConly: if 1 and when a process has to be started, the process will only be started if the device is on external power

The scheduler

First, tasker2 is normally only launched one time manually and all future calls are made by the scheduler. Tasker2 will clear and schedule all planned tasks as defined in the registry if it is launched without arguments.

The scheduler is a task manager running all the time in windows mobile. If a timed schedule is reached, the scheduler will launch the specified application, see also here . This will also work if the device is in suspend mode (sleeps). The scheduler can also fire on special events like time or hardware changes (ON_RS232_CONNECT for example). See also my post here [http://www.hjgode.de/wp/2010/03/06/irunatevent/].

Theory of operation

Tasker2 uses command line arguments to control itself. The scheduler launches tasker2 with the specified arguments and tasker2 will then run or kill the defined task.

Delayed schedules (pitfall 1)

If your device supports a real power down, the scheduler will not awake the device and is not able to launch the defined schedules. When the device is later powered on, it will schedule all past schedules at once. This is what we call a ‘delayed schedule’ and a flooding of launches. Flooding in the mean of many schedules of tasker2 occurring at the same time for past tasks.
To avoid concurrent changes to the registry and scheduler entries, tasker2 uses a mutex to ensure only one instance is continuing execution. Subsequent instances will wait for existing instances before they do there work.

<ol><li class="li1"><div class="de1"><span class="co1">//##################### dont run if already running #############################</span></div></li><li class="li1"><div class="de1">	nclog<span class="br0">(</span>L<span class="st0">"Checking for Mutex (single instance allowed only)...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	hMutex<span class="sy1">=</span>CreateMutex<span class="br0">(</span><span class="kw2">NULL</span>, TRUE, MY_MUTEX<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="kw1">if</span><span class="br0">(</span>hMutex<span class="sy1">==</span><span class="kw2">NULL</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">		<span class="co1">//this should never happen</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"Error in CreateMutex! GetLastError()=%i<span class="es1">\n</span>"</span>, GetLastError<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"-------- END -------<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw1">return</span> <span class="sy2">-</span><span class="nu0">99</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span></div></li><li class="li1"><div class="de1">	DWORD dwLast <span class="sy1">=</span> GetLastError<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="kw1">if</span><span class="br0">(</span>dwLast<span class="sy1">==</span> ERROR_ALREADY_EXISTS<span class="br0">)</span><span class="br0">{</span><span class="co1">//mutex already exists, wait for mutex release</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>Attached to existing mutex<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"................ Waiting for mutex release......<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		WaitForSingleObject<span class="br0">(</span> hMutex, INFINITE <span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"++++++++++++++++ Mutex released. +++++++++++++++<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span></div></li><li class="li1"><div class="de1">	<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>Created new mutex<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="co1">//##################### dont run if already running #############################</span></div></li></ol>

On a delayed, flooding schedule ALL pending tasks are scheduled and possibly a Time_Changed string is sent to the pending tasks. This flooding will be serialized as tasker2 waits for existing tasker2 instances.

Time and time zone changes (pitfall 2)

When the time is changed on the device, the scheduler will inform all timed tasks. Tasker2 must then recalculate new schedules based on current local time. The scheduler launches the defined applications with the TIME_CHANGED string as argument.

<ol><li class="li1"><div class="de1"><span class="kw1">else</span> <span class="kw1">if</span><span class="br0">(</span>wcsicmp<span class="br0">(</span>argv<span class="br0">[</span>1<span class="br0">]</span>, APP_RUN_AFTER_TIME_CHANGE<span class="br0">)</span><span class="sy1">==</span>0 <span class="sy3">||</span> wcsicmp<span class="br0">(</span>argv<span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span>, APP_RUN_AFTER_TZ_CHANGE<span class="br0">)</span><span class="sy1">==</span><span class="nu0">0</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"got '%s' signaled<span class="es1">\n</span>"</span>, argv<span class="br0">[</span>1<span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="co1">//better to reread the current time we work with, possibly we have been blocked</span></div></li><li class="li1"><div class="de1">				g_tmCurrentStartTime<span class="sy1">=</span>getLocalTime<span class="br0">(</span><span class="sy3">&</span>g_tmCurrentStartTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="co1">//now again check if we have a valid date</span></div></li><li class="li1"><div class="de1">				nclog<span class="br0">(</span>L<span class="st0">"Checking for valid date/time...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="kw1">if</span><span class="br0">(</span> <span class="br0">(</span><span class="br0">(</span>g_tmCurrentStartTime.<span class="me1">tm_year</span><span class="sy2">+</span><span class="nu0">1900</span><span class="br0">)</span><span class="sy2">*</span><span class="nu0">100</span> <span class="sy2">+</span> g_tmCurrentStartTime.<span class="me1">tm_mon</span><span class="sy2">+</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy1"><</span> <span class="nu0">201111</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">					nclog<span class="br0">(</span>L<span class="st0">"scheduling event notifications<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="co1">//clear and renew all event notifications</span></div></li><li class="li1"><div class="de1">					<span class="co2">#ifndef TESTMODE</span></div></li><li class="li1"><div class="de1">						RunAppAtTimeChangeEvents<span class="br0">(</span>szTaskerEXE<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="co2">#endif</span></div></li><li class="li1"><div class="de1">					nclog<span class="br0">(</span>L<span class="st0">"Date/Time not valid!<span class="es1">\n</span>*********** END ************<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="kw1">return</span> <span class="nu12">0xBADCAB1E</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="br0">}</span></div></li><li class="li1"><div class="de1">				nclog<span class="br0">(</span>L<span class="st0">"Date/Time after 11 2011. OK<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">			<span class="co1">//schedule all active tasks</span></div></li><li class="li1"><div class="de1">			<span class="kw4">int</span> iCount <span class="sy1">=</span> scheduleAllTasks<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"Scheduled %i Tasks<span class="es1">\n</span>"</span>, iCount<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li></ol>

Additionally we found that the time changes may also occur during program launch or as tasker2 instances wait for another tasker2 instance. So tasker2 uses only one (in real two) calls to get the current time. This is essential, as tasker2 uses the current time to re-schedule tasks. The current time is called at the beginning, before tasker2 waits for the mutex. This is the time tasker2 was launched. If there has been a time_changed schedule, tasker2 will use another call to the current time, as it may have changed between the launch and the further execution of the code – after the mutex is released and the current instance is allowed to run.

Delayed schedules II (pitfall 3)

As only one instance of tasker2 is executing, it may happen, that the current time and the task time do not match exactly. Although the scheduler may do its best to launch tasker2 at the right time, the execution may be delayed in regards of the time the task is to be scheduled and the current time. This is another delayed schedule compared to the above flooding of schedules after a power down/up cycle.
It may also happen that a lot of tasker2 instances are waiting for execution, you know that we can have up to ten tasks. This may also lead to ‘delayed’ code execution, but should be in a small time frame of some minutes only.
Therefor tasker2 supports a maximum allowed delay time to distinguish between allowed and flooding delayed calls.

<ol><li class="li1"><div class="de1"><span class="co1">//is this a delayed schedule?</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>checking for delayed schedule...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw4">int</span> iDeltaMinutes<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttStart<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttStop<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttCurr<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttStop <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttStart <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttCurr <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span>g_tmCurrentStartTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			<span class="co1">//difftime(timer1, timer0) returns the elapsed time in seconds, from timer0 to timer1</span></div></li><li class="li1"><div class="de1">			iDeltaMinutes <span class="sy1">=</span> <span class="kw3">difftime</span><span class="br0">(</span>ttCurr, ttStop<span class="br0">)</span><span class="sy2">/</span><span class="nu0">60</span><span class="sy4">;</span><span class="co1">// stDeltaMinutes(_Tasks[iTask].stStopTime, g_CurrentStartTime);</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"stStopTime = '%s', "</span>, getLongStrFromTM<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			iDeltaMinutes <span class="sy1">=</span> <span class="kw3">difftime</span><span class="br0">(</span>ttStart, ttCurr<span class="br0">)</span><span class="sy2">/</span><span class="nu0">60</span><span class="sy4">;</span><span class="co1">// stDeltaMinutes(_Tasks[iTask].stStartTime, g_CurrentStartTime);</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"stStartTime = '%s', "</span>, getLongStrFromTM<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li></ol>

Adding a schedule

I am using central functions in code to add or remove schedules. Here is a sample of how a schedule is added:

<ol><li class="li1"><div class="de1">...</div></li><li class="li1"><div class="de1"><span class="co2">#include "notify.h"</span></div></li><li class="li1"><div class="de1">...</div></li><li class="li1"><div class="de1"><span class="co1">//--------------------------------------------------------------------</span></div></li><li class="li1"><div class="de1"><span class="co1">// Function name  : ScheduleRunApp</span></div></li><li class="li1"><div class="de1"><span class="co1">// Description    : add a schedule for exe with args at the time</span></div></li><li class="li1"><div class="de1"><span class="co1">// Argument       : LPCTSTR szExeName</span></div></li><li class="li1"><div class="de1"><span class="co1">// Argument       : LPCTSTR szArgs</span></div></li><li class="li1"><div class="de1"><span class="co1">// Argument       : struct tm tmTime</span></div></li><li class="li1"><div class="de1"><span class="co1">// Return type    : HRESULT, 0 for no error</span></div></li><li class="li1"><div class="de1"><span class="co1">//--------------------------------------------------------------------</span></div></li><li class="li1"><div class="de1">HRESULT ScheduleRunApp<span class="br0">(</span>LPCTSTR szExeName, LPCTSTR szArgs, <span class="kw4">struct</span> <span class="kw4">tm</span> tmTime<span class="br0">)</span></div></li><li class="li1"><div class="de1"><span class="br0">{</span></div></li><li class="li1"><div class="de1">	HRESULT hr <span class="sy1">=</span> S_OK<span class="sy4">;</span></div></li><li class="li1"><div class="de1">	HANDLE hNotify <span class="sy1">=</span> <span class="kw2">NULL</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="co1">// set a CE_NOTIFICATION_TRIGGER</span></div></li><li class="li1"><div class="de1">	CE_NOTIFICATION_TRIGGER notifTrigger<span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="kw3">memset</span><span class="br0">(</span><span class="sy3">&</span>notifTrigger, 0, <span class="kw3">sizeof</span><span class="br0">(</span>CE_NOTIFICATION_TRIGGER<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	notifTrigger.<span class="me1">dwSize</span> <span class="sy1">=</span> <span class="kw3">sizeof</span><span class="br0">(</span>CE_NOTIFICATION_TRIGGER<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="co1">// calculate time</span></div></li><li class="li1"><div class="de1">	SYSTEMTIME st <span class="sy1">=</span> <span class="br0">{</span>0<span class="br0">}</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="co1">//GetLocalTime(&st); //v.2.28</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	st <span class="sy1">=</span> convertTM2SYSTEMTIME<span class="br0">(</span><span class="sy3">&</span>st, <span class="sy3">&</span>tmTime<span class="br0">)</span><span class="sy4">;</span> <span class="co1">//use provided new datetime</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	wsprintf<span class="br0">(</span>str, L<span class="st0">"Next run at: %02i.%02i.%02i %02i:%02i:%02i"</span>,</div></li><li class="li1"><div class="de1">										st.<span class="me1">wDay</span>, st.<span class="me1">wMonth</span> , st.<span class="me1">wYear</span>,</div></li><li class="li1"><div class="de1">										st.<span class="me1">wHour</span> , st.<span class="me1">wMinute</span> , st.<span class="me1">wSecond</span> <span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>ScheduleRunApp: %s<span class="es1">\n</span>"</span>, str<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	notifTrigger.<span class="me1">dwType</span> <span class="sy1">=</span> CNT_TIME<span class="sy4">;</span></div></li><li class="li1"><div class="de1">	notifTrigger.<span class="me1">stStartTime</span> <span class="sy1">=</span> st<span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="co1">// timer: execute an exe at specified time</span></div></li><li class="li1"><div class="de1">	notifTrigger.<span class="me1">lpszApplication</span> <span class="sy1">=</span> <span class="br0">(</span>LPTSTR<span class="br0">)</span>szExeName<span class="sy4">;</span></div></li><li class="li1"><div class="de1">	notifTrigger.<span class="me1">lpszArguments</span> <span class="sy1">=</span> <span class="br0">(</span>LPTSTR<span class="br0">)</span>szArgs<span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	hNotify <span class="sy1">=</span> CeSetUserNotificationEx<span class="br0">(</span>0, <span class="sy3">&</span>notifTrigger, <span class="kw2">NULL</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="co1">// NULL because we do not care the action</span></div></li><li class="li1"><div class="de1">	<span class="kw1">if</span> <span class="br0">(</span><span class="sy3">!</span>hNotify<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1">		hr <span class="sy1">=</span> E_FAIL<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>ScheduleRunApp: CeSetUserNotificationEx FAILED...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span> <span class="kw1">else</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1">		<span class="co1">// close the handle as we do not need to use it further</span></div></li><li class="li1"><div class="de1">		CloseHandle<span class="br0">(</span>hNotify<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>ScheduleRunApp: CeSetUserNotificationEx succeeded...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span></div></li><li class="li1"><div class="de1">	<span class="kw1">return</span> hr<span class="sy4">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol>

The main code

The main function is processStartStopCmd() beside createNextSchedule(). It does all the scheduling and time calculations.

<ol><li class="li1"><div class="de1"><span class="coMULTI">/*	########################################################</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">		Process -s and -k comd line args</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">	########################################################</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">*/</span></div></li><li class="li1"><div class="de1"><span class="co1">//--------------------------------------------------------------------</span></div></li><li class="li1"><div class="de1"><span class="co1">// Function name  : processStartStopCmd</span></div></li><li class="li1"><div class="de1"><span class="co1">// Description    : calc new start/stop time, add schedules and start/kill application</span></div></li><li class="li1"><div class="de1"><span class="co1">// Argument       : TCHAR* argv[], the cmdLine array</span></div></li><li class="li1"><div class="de1"><span class="co1">// Return type    : int, 0 for no error</span></div></li><li class="li1"><div class="de1"><span class="co1">//--------------------------------------------------------------------</span></div></li><li class="li1"><div class="de1"><span class="kw4">int</span> processStartStopCmd<span class="br0">(</span>TCHAR<span class="sy2">*</span> argv<span class="br0">[</span><span class="br0">]</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">	<span class="kw4">int</span> iReturn <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	BOOL bIsDelayedSchedule <span class="sy1">=</span> TRUE<span class="sy4">;</span> <span class="co1">//used to save a delayed schedule situation</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="kw2">enum</span> taskType<span class="br0">{</span></div></li><li class="li1"><div class="de1">		startTask <span class="sy1">=</span> 1,</div></li><li class="li1"><div class="de1">		stopTask <span class="sy1">=</span> 2</div></li><li class="li1"><div class="de1">	<span class="br0">}</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	taskType thisTaskType<span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="kw1">if</span><span class="br0">(</span>wcsicmp<span class="br0">(</span>argv<span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span>, L<span class="st0">"-k"</span><span class="br0">)</span><span class="sy1">==</span><span class="nu0">0</span><span class="br0">)</span>	<span class="co1">//kill taskX app</span></div></li><li class="li1"><div class="de1">		thisTaskType<span class="sy1">=</span>stopTask<span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="kw1">else</span></div></li><li class="li1"><div class="de1">		thisTaskType<span class="sy1">=</span>startTask<span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">	<span class="kw4">int</span> iTask <span class="sy1">=</span> getTaskNumber<span class="br0">(</span>argv<span class="br0">[</span>2<span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">	<span class="kw1">if</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">iActive</span><span class="sy1">==</span><span class="nu0">1</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">		<span class="co1">//create a new schedule cmd line for tasker</span></div></li><li class="li1"><div class="de1">		TCHAR strTaskCmdLine<span class="br0">[</span>MAX_PATH<span class="br0">]</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span></div></li><li class="li1"><div class="de1">			wsprintf<span class="br0">(</span>strTaskCmdLine, L<span class="st0">"-k task%i"</span>, iTask<span class="sy2">+</span>1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">//the cmdLine for tasker.exe for this task</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span></div></li><li class="li1"><div class="de1">			wsprintf<span class="br0">(</span>strTaskCmdLine, L<span class="st0">"-s task%i"</span>, iTask<span class="sy2">+</span>1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">//the cmdLine for tasker.exe for this task	</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="co1">//clear all tasker schedules for taskX</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"Clearing all schedules for Task%i with '%s'<span class="es1">\n</span>"</span>, iTask<span class="sy2">+</span>1, strTaskCmdLine<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		notiClearRunApp<span class="br0">(</span>szTaskerEXE, strTaskCmdLine<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw4">struct</span> <span class="kw4">tm</span> tmNewTime <span class="sy1">=</span> <span class="br0">{</span>0<span class="br0">}</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw4">short</span> shHour	<span class="sy1">=</span>	_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stDiffTime</span>.<span class="me1">tm_hour</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw4">short</span> shMin		<span class="sy1">=</span>	_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stDiffTime</span>.<span class="me1">tm_min</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw4">short</span> shDays	<span class="sy1">=</span>	<span class="nu0">0</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>shHour<span class="sy1">>=</span><span class="nu0">24</span><span class="br0">)</span><span class="br0">{</span>	<span class="co1">//hour interval value is one day or more</span></div></li><li class="li1"><div class="de1">			shDays <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">short</span><span class="br0">)</span> <span class="br0">(</span>shHour <span class="sy2">/</span> 24<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			shHour <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">short</span><span class="br0">)</span> <span class="br0">(</span>shHour <span class="sy2">%</span> 24<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span>				</div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="co1">//is this a delayed schedule?</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>checking for delayed schedule...<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw4">int</span> iDeltaMinutes<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttStart<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttStop<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		__time64_t ttCurr<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttStop <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttStart <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		ttCurr <span class="sy1">=</span> _mktime64<span class="br0">(</span><span class="sy3">&</span>g_tmCurrentStartTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			<span class="co1">//difftime(timer1, timer0) returns the elapsed time in seconds, from timer0 to timer1</span></div></li><li class="li1"><div class="de1">			iDeltaMinutes <span class="sy1">=</span> <span class="kw3">difftime</span><span class="br0">(</span>ttCurr, ttStop<span class="br0">)</span><span class="sy2">/</span><span class="nu0">60</span><span class="sy4">;</span><span class="co1">// stDeltaMinutes(_Tasks[iTask].stStopTime, g_CurrentStartTime);</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"stStopTime = '%s', "</span>, getLongStrFromTM<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			iDeltaMinutes <span class="sy1">=</span> <span class="kw3">difftime</span><span class="br0">(</span>ttStart, ttCurr<span class="br0">)</span><span class="sy2">/</span><span class="nu0">60</span><span class="sy4">;</span><span class="co1">// stDeltaMinutes(_Tasks[iTask].stStartTime, g_CurrentStartTime);</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"stStartTime = '%s', "</span>, getLongStrFromTM<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"current time = '%s'<span class="es1">\n</span>"</span>, getLongStrFromTM<span class="br0">(</span>g_tmCurrentStartTime<span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"interval is: %id%02ih%02im<span class="es1">\n</span>"</span>, shDays, shHour, shMin<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>delta is %i minutes<span class="es1">\n</span>"</span>, iDeltaMinutes<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="co1">//started BEFORE scheduled time, iDelta is negative</span></div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>iDeltaMinutes<span class="sy1"><</span>0<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">				<span class="co1">//calculate new schedules or leave them as is?</span></div></li><li class="li1"><div class="de1">				<span class="co1">//tmNewTime=_Tasks[iTask].stStopTime;	//leave them as is</span></div></li><li class="li1"><div class="de1">				tmNewTime<span class="sy1">=</span>createNextSchedule<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span>, shDays,shHour,shMin<span class="br0">)</span><span class="sy4">;</span> <span class="co1">//calc new schedule</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1">			<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">				<span class="co1">//tmNewTime=_Tasks[iTask].stStartTime;	//leave them as is</span></div></li><li class="li1"><div class="de1">				tmNewTime<span class="sy1">=</span>createNextSchedule<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span>, shDays,shHour,shMin<span class="br0">)</span><span class="sy4">;</span> <span class="co1">//calc new schedule</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="co2">#ifndef TESTMODE</span></div></li><li class="li1"><div class="de1">			ScheduleRunApp<span class="br0">(</span>szTaskerEXE, strTaskCmdLine, tmNewTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"><span class="co2">#endif</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"*** re-scheduled future task *** <span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw4">int</span> iMaxDelay <span class="sy1">=</span> getMaxDelay<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>max allowed diff for delayed schedule recognition is plus %i<span class="es1">\n</span>"</span>, iMaxDelay<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span> iDeltaMinutes <span class="sy1">></span> iMaxDelay <span class="br0">)</span> <span class="co1">//is the time diff greater than 1 minute</span></div></li><li class="li1"><div class="de1">		<span class="br0">{</span></div></li><li class="li1"><div class="de1">			bIsDelayedSchedule <span class="sy1">=</span> TRUE<span class="sy4">;</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"*** delayed schedule *** recognized<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="co1">//this is a delayed schedule</span></div></li><li class="li1"><div class="de1">			DOUBLE dbTimeDiff <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">			<span class="co1">//it may happen that the schedule is far in the future</span></div></li><li class="li1"><div class="de1">			<span class="co1">//we calc the next schedule on base of the current time by using the saved start/stop time</span></div></li><li class="li1"><div class="de1">			<span class="co1">//is just greater than the current time</span></div></li><li class="li1"><div class="de1">			<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span></div></li><li class="li1"><div class="de1">				tmNewTime<span class="sy1">=</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="kw1">else</span></div></li><li class="li1"><div class="de1">				tmNewTime<span class="sy1">=</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">			tmNewTime <span class="sy1">=</span> createNextSchedule<span class="br0">(</span>tmNewTime, shDays, shHour, shMin<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"*** NO delayed schedule *** recognized<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">				tmNewTime <span class="sy1">=</span> createNextSchedule<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStopTime</span>, shDays, shHour, shMin<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1">			<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">				tmNewTime <span class="sy1">=</span> createNextSchedule<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">stStartTime</span>, shDays, shHour, shMin<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1">			bIsDelayedSchedule<span class="sy1">=</span>FALSE<span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="co1">//create a new kill or start schedule with new time</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"Creating new schedule for '%s' in Task%i<span class="es1">\n</span>"</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span>, iTask<span class="sy2">+</span>1<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"><span class="co2">#ifndef TESTMODE</span></div></li><li class="li1"><div class="de1">		ScheduleRunApp<span class="br0">(</span>szTaskerEXE, strTaskCmdLine, tmNewTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"><span class="co2">#endif</span></div></li><li class="li1"><div class="de1">		<span class="co1">//save new changed stop/start ime</span></div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>stopTask<span class="br0">)</span></div></li><li class="li1"><div class="de1">			regSetStopTime<span class="br0">(</span>iTask, tmNewTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span></div></li><li class="li1"><div class="de1">			regSetStartTime<span class="br0">(</span>iTask, tmNewTime<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">if</span><span class="br0">(</span><span class="sy3">!</span>bIsDelayedSchedule<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"Not a delayed schedule<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">			<span class="kw1">if</span><span class="br0">(</span>thisTaskType<span class="sy1">==</span>startTask<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">				<span class="kw1">if</span><span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">bStartOnAConly</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">					<span class="kw1">if</span><span class="br0">(</span>isACpowered<span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">						nclog<span class="br0">(</span>L<span class="st0">"Starting exe '%s' as on AC power<span class="es1">\n</span>"</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">						runExe<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szArgs</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="br0">}</span></div></li><li class="li1"><div class="de1">					<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">						nclog<span class="br0">(</span>L<span class="st0">"Skipping start of exe '%s' as not on AC power<span class="es1">\n</span>"</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="br0">}</span></div></li><li class="li1"><div class="de1">				<span class="br0">}</span></div></li><li class="li1"><div class="de1">				<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">					nclog<span class="br0">(</span>L<span class="st0">"Starting exe '%s'<span class="es1">\n</span>"</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					runExe<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szArgs</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="br0">}</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1">			<span class="kw1">else</span><span class="br0">{</span> <span class="co1">// a stop task</span></div></li><li class="li1"><div class="de1">				<span class="co1">//now kill the task's exe</span></div></li><li class="li1"><div class="de1">				nclog<span class="br0">(</span>L<span class="st0">"Killing exe '%s'<span class="es1">\n</span>"</span>, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				DWORD iKillRes <span class="sy1">=</span> killExe<span class="br0">(</span>_Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">szExeName</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="kw1">switch</span> <span class="br0">(</span>iKillRes<span class="br0">)</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">					<span class="kw1">case</span> ERROR_NOT_FOUND<span class="sy4">:</span></div></li><li class="li1"><div class="de1">						nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>exe not running<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">						<span class="kw1">break</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="kw1">case</span> <span class="nu0">0</span><span class="sy4">:</span></div></li><li class="li1"><div class="de1">						nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>exe killed<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">						<span class="kw1">break</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">					<span class="kw1">default</span><span class="sy4">:</span></div></li><li class="li1"><div class="de1">						nclog<span class="br0">(</span>L<span class="st0">"unable to kill exe. GetLastError=%08x<span class="es1">\n</span>"</span>, iKillRes<span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">						<span class="kw1">break</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">				<span class="br0">}</span></div></li><li class="li1"><div class="de1">			<span class="br0">}</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1">		<span class="kw1">else</span><span class="br0">{</span></div></li><li class="li1"><div class="de1">			nclog<span class="br0">(</span>L<span class="st0">"Exec/Kill skipped as this is a delayed schedule<span class="es1">\n</span>"</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1">		<span class="br0">}</span></div></li><li class="li1"><div class="de1">	<span class="br0">}</span></div></li><li class="li1"><div class="de1">	<span class="kw1">else</span></div></li><li class="li1"><div class="de1">		nclog<span class="br0">(</span>L<span class="st0">"<span class="es1">\t</span>task %i is inactive (0x%02x)<span class="es1">\n</span>"</span>, iTask, _Tasks<span class="br0">[</span>iTask<span class="br0">]</span>.<span class="me1">iActive</span><span class="br0">)</span><span class="sy4">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">		<span class="kw1">return</span> iReturn<span class="sy4">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol>

 Tasker2 control

Although you normally dont need to run tasker2 manually, I have added some command line arguments:

“-c”    instructs tasker2.exe to remove all tasker2 schedules of the scheduler database
“-r taskX”    deactivate processing of task with number X, sets the active flag to 0
“-a taskX”    activate processing of task number X, sets the active flag to 1
“-d”    dump a list of all active notifications of the windows mobile scheduler

Do not use -s taskX and -k taskX except for testing. The args ‘-s taskX’ and ‘-k taskX’ are only be used by the scheduler.

Log file

The log file will log all activities of tasker2 in the directory of tasker2.exe. It will grow until 1MB and then one log backup file is saved. So you may have two log files, one active and one backup of the previous log.

<ol><li class="li1"><div class="de1">0xfacbcab2: ++++++++++++++++ Tasker v300 started +++++++++++++++++++</div></li><li class="li1"><div class="de1">0xfacbcab2: Checking <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> Mutex <span class="br0">(</span>single instance allowed only<span class="br0">)</span>...</div></li><li class="li1"><div class="de1">0xfacbcab2: 	Created new mutex</div></li><li class="li1"><div class="de1">0xfacbcab2: ~~~ using actual localtime:</div></li><li class="li1"><div class="de1">0xfacbcab2: 	 23.12.2011, 12:28</div></li><li class="li1"><div class="de1">0xfacbcab2: CmdLine =</div></li><li class="li1"><div class="de1">0xfacbcab2: Checking <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> valid date/time...</div></li><li class="li1"><div class="de1">0xfacbcab2: Date/Time after 11 2011. OK</div></li><li class="li1"><div class="de1">0xfacbcab2: Clearing Event Notifications...0xfacbcab2: OK</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: ...</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3d00000f</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x33000025</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3800002a</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3b00001b</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3800002e</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3f00001e</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x37000016</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: CeClearUserNotification <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> handle: 0x3a000030</div></li><li class="li1"><div class="de1">0xfacbcab2: ClearRunApp<span class="br0">(</span><span class="br0">)</span>: returns 8</div></li><li class="li1"><div class="de1">0xfacbcab2: Cleared 8 Tasker schedules</div></li><li class="li1"><div class="de1">0xfacbcab2: scheduleAllTasks: ClearAllSchedules <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> 8 tasks</div></li><li class="li1"><div class="de1">0xfacbcab2: Clearing Event Notifications...0xfacbcab2: Clearing Event Notifications...0xfacbcab2: OK</div></li><li class="li1"><div class="de1">0xfacbcab2: Adding Time_Change Event Notification...0xfacbcab2: OK</div></li><li class="li1"><div class="de1">0xfacbcab2: Adding TZ_Change Event Notification...0xfacbcab2: OK</div></li><li class="li1"><div class="de1">0xfacbcab2: Creating new Start Task schedule <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> '\Windows\notes.exe' <a href="http://www.ss64.com/nt/in.html"><span class="kw1">in</span></a> Task1</div></li><li class="li1"><div class="de1">0xfacbcab2: 	calculating new schedule <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> '201112231300'...</div></li><li class="li1"><div class="de1">0xfacbcab2: 	interval is: 0d01h00m</div></li><li class="li1"><div class="de1">0xfacbcab2: 	schedule adjusted to '201112231300'</div></li><li class="li1"><div class="de1">0xfacbcab2: 	ScheduleRunApp: Next run at: 23.12.2011 13:00:56</div></li><li class="li1"><div class="de1">0xfacbcab2: 	ScheduleRunApp: CeSetUserNotificationEx succeeded...</div></li><li class="li1"><div class="de1">0xfacbcab2: Creating new Kill Task schedule <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> '\Windows\notes.exe' <a href="http://www.ss64.com/nt/in.html"><span class="kw1">in</span></a> Task1</div></li><li class="li1"><div class="de1">0xfacbcab2: 	calculating new schedule <a href="http://www.ss64.com/nt/for.html"><span class="kw1">for</span></a> '<span class="nu0">201112231300</span>'...</div></li><li class="li1"><div class="de1">0xfacbcab2: 	interval is: 0d01h00m</div></li><li class="li1"><div class="de1">0xfacbcab2: 	schedule adjusted to '<span class="nu0">201112231300</span>'</div></li><li class="li1"><div class="de1">0xfacbcab2: 	ScheduleRunApp: Next run at: 23.12.2011 <span class="nu0">13</span>:00:<span class="nu0">56</span></div></li><li class="li1"><div class="de1">0xfacbcab2: 	ScheduleRunApp: CeSetUserNotificationEx succeeded...</div></li><li class="li1"><div class="de1">...</div></li></ol>

The first entry in the log file is the current logging instance. As multiple instances may write randomly at the log, the instance number is needed to idetify which instance has written the current log line.

Changes

There are two variants of tasker2, one is using SYSTEMTIME and the other, new one uses time_t. I switched to time_t as it is more easy to do operations like add-one-day with time_t vars than with SYSTEMTIME.

The old variant (v234a) is available as a branch in the code repository: http://code.google.com/p/tasker2/source/browse/#svn%2Fbranch%2Fversion232%2FTasker

Tests

Fortunately I had great help by a tester of the software. Many thanks to Thomas B.

I built my only automatic test suite using batch files and a special build of tasker2.exe. If you uncomment the line //#define TESTMODE at the beginning of tasker2.cpp, the compiled app will be in test mode. That means it will not add or remove schedules to/from the windows mobile scheduler. There is another tool used in the test_run.bat that sets the date and time of the device remotely (ActiveSync or Windows Mobile Device Center connection).

The automatic test uses the great tools of itsutils and will set registry values, change date/time, launch tasker2, get the log and build a merged log with all essential data to check the function of tasker2:

http://code.google.com/p/tasker2/source/browse/#svn%2Ftrunk%2FTasker%2Ftest

Here is a snippet from the test_bat.bat:

<ol><li class="li1"><div class="de1"><span class="sy0">@</span><span class="kw1">echo</span> off</div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="co2">############## START ###############</span></div></li><li class="li1"><div class="de1"><span class="kw1">echo</span>  MAKE SHURE THE RADIOS ARE OFF TO</div></li><li class="li1"><div class="de1"><span class="kw1">echo</span>  AVOID AUTOMATIC <a href="http://www.php.net/time"><span class="kw3">TIME</span></a> SYNCS<span class="sy0">!</span></div></li><li class="li1"><div class="de1"><span class="kw1">echo</span> <span class="sy0">.</span></div></li><li class="li1"><div class="de1">PAUSE Press any <a href="http://www.php.net/key"><span class="kw3">key</span></a> to start</div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="co2">############## START ############### >test_run.txt</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="kw1">echo</span> Importing test reg keys<span class="sy0">...</span></div></li><li class="li1"><div class="de1"><span class="kw1">echo</span> Importing test reg keys<span class="sy0">...</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">pregutl <span class="sy0">@</span>tasker2<span class="sy0">.</span>reg <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1">pdel \tasker2<span class="sy0">.</span>exe<span class="sy0">.</span><a href="http://www.php.net/log"><span class="kw3">log</span></a><span class="sy0">.</span>txt <span class="sy0">></span>NUL</div></li><li class="li1"><div class="de1">pput <span class="sy0">-</span>f <span class="sy0">./</span>tasker2<span class="sy0">.</span>exe \tasker2<span class="sy0">.</span>exe</div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> TEST1<span class="sy0">...</span></div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> 	set <a href="http://www.php.net/time"><span class="kw3">time</span></a> manually to 01<span class="sy0">.</span>01<span class="sy0">.</span>2003 12<span class="sy0">:</span>00</div></li><li class="li1"><div class="de1"><span class="kw1">echo</span> 	run tasker2<span class="sy0">.</span>exe</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">++++++++++++++</span> TEST1 <span class="sy0">++++++++++++++++</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">pregutl HKLM\Software\Tasker  <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">-------------------------------------</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> set <a href="http://www.php.net/time"><span class="kw3">time</span></a> manually to 01<span class="sy0">.</span>01<span class="sy0">.</span>2003 12<span class="sy0">:</span>00 <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">-------------------------------------</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">prun \SetDateTime<span class="sy0">.</span>exe 200301011200</div></li><li class="li1"><div class="de1">CALL <span class="sy0">:</span>MYWAIT</div></li><li class="li1"><div class="de1">prun \tasker2<span class="sy0">.</span>exe</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="st0">"############# Result:"</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">pregutl HKLM\Software\Tasker <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">***************</span> <a href="http://www.php.net/log"><span class="kw3">LOG</span></a>  <span class="sy0">****************</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">pget <span class="sy0">-</span>f \tasker2<span class="sy0">.</span>exe<span class="sy0">.</span><a href="http://www.php.net/log"><span class="kw3">log</span></a><span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">type tasker2<span class="sy0">.</span>exe<span class="sy0">.</span><a href="http://www.php.net/log"><span class="kw3">log</span></a><span class="sy0">.</span>txt <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1">pdel \tasker2<span class="sy0">.</span>exe<span class="sy0">.</span><a href="http://www.php.net/log"><span class="kw3">log</span></a><span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">---------------</span>TEST1  <span class="sy0">---------------</span> <span class="sy0">>></span>test_run<span class="sy0">.</span>txt</div></li><li class="li1"><div class="de1"><span class="kw1">ECHO</span> <span class="sy0">.>></span>test_run<span class="sy0">.</span>txt</div></li></ol>

Downloads

The full tasker2 source code is available at http://code.google.com/p/tasker2/source/browse

Tool to look at the scheduler database [NotificationList]: DOWNLOAD:NotificationList - A tool to list notifications (Hits: 1, size: 153.42 kB)

 

<!-- Social Bookmarks BEGIN --> <!-- Social Bookmarks END -->

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here