I have a managed component written in C # that is hosted by an inherited Win32 application as an ActiveX control. Inside my component, I need to get what usually will be Application.Idle, i.e. Get a time slice of the processing time in standby mode user interface thread (it should be the main user interface thread).
However, this hosted script Application.Idledoes not start because there is no controlled message loop (i.e. no Application.Run).
Unfortunately, the host also does not implement IMsoComponentManager, which may be suitable for what I need. And a long nested message loop (s Application.DoEvents) is not an option for many reasons.
So far, the only solution I can come up with is to use simple Win32 timers . According to http://support.microsoft.com/kb/96006 , it WM_TIMERhas one of the lowest priorities, followed only by one WM_PAINT, which should be as close to me as possible.
Are there any other options for this scenario?
Here is the prototype code:
while (true)
{
token.ThrowIfCancellationRequested();
await TimerYield(DELAY, token);
if (Win32.GetQueueStatus(Win32.QS_KEY | Win32.QS_MOUSE) >> 16 != 0)
continue;
}
static async Task TimerYield(int delay, CancellationToken token)
{
var tcs = new TaskCompletionSource<bool>();
using (var timer = new System.Windows.Forms.Timer())
using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
{
timer.Interval = delay;
timer.Tick += (s, e) => tcs.TrySetResult(true);
timer.Enabled = true;
await tcs.Task;
timer.Enabled = false;
}
}
I do not think it Task.Delayis suitable for this approach, since it uses kernel timer objects that are independent of the message loop and its priorities.
. : WH_FOREGROUNDIDLE/ForegroundIdleProc. , .
, , Win32 WPF Dispatcher, .. Dispatcher.BeginInvoke(DispatcherPriority.Background, ...):