Last active
January 22, 2021 06:39
-
-
Save NDiiong/e101dbbaec7cdacdc368954e90a4fe1b to your computer and use it in GitHub Desktop.
AsyncTask.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AsyncTask : IDisposable | |
{ | |
private readonly bool _envDTETask; | |
private readonly object _objlock = new object(); | |
private readonly TaskFunction _taskFunction; | |
private readonly Thread _thread; | |
private readonly AutoResetEvent _wakeEvent = new AutoResetEvent(false); | |
private volatile bool _exiting; | |
private volatile int _startTime; | |
private TaskContext _taskContext; | |
public AsyncTask(TaskFunction task, string name) : this(task, name, dteTask: false) | |
{ | |
} | |
public AsyncTask(TaskFunction task, string name, bool dteTask) | |
{ | |
_taskFunction = task; | |
_envDTETask = dteTask; | |
_thread = new Thread(ThreadMain) | |
{ | |
Name = name | |
}; | |
if (dteTask) | |
{ | |
_thread.SetApartmentState(ApartmentState.STA); | |
} | |
_thread.Start(); | |
} | |
public delegate void TaskFunction(TaskContext context); | |
public void Exit() | |
{ | |
Cancel(); | |
_exiting = true; | |
_wakeEvent.Set(); | |
} | |
public void Start() | |
{ | |
Start(0); | |
} | |
public void Start(int delay) | |
{ | |
Start(new TaskContext(null), delay); | |
} | |
public void Start(TaskContext taskContext) | |
{ | |
Start(taskContext, 0); | |
} | |
public void Start(TaskContext taskContext, int delay) | |
{ | |
int start_time = Environment.TickCount + delay; | |
lock (_objlock) | |
{ | |
bool alreadyStarted = false; | |
if (_taskContext != null) | |
{ | |
_taskContext.Cancel(); | |
alreadyStarted = true; | |
} | |
_taskContext = taskContext; | |
if (!alreadyStarted || start_time > _startTime) | |
{ | |
_startTime = start_time; | |
} | |
_wakeEvent.Set(); | |
} | |
} | |
private void ThreadMain() | |
{ | |
while (!_exiting) | |
{ | |
int start_time; | |
TaskContext taskContext; | |
lock (_objlock) | |
{ | |
start_time = _startTime; | |
taskContext = _taskContext; | |
} | |
while ((start_time == 0 || start_time > Environment.TickCount) && !_exiting) | |
{ | |
int sleep_time = ((start_time != 0) ? Math.Max(0, start_time - Environment.TickCount) : (-1)); | |
_wakeEvent.WaitOne(sleep_time); | |
lock (_objlock) | |
{ | |
start_time = _startTime; | |
taskContext = _taskContext; | |
} | |
} | |
if (_exiting || taskContext == null) | |
{ | |
continue; | |
} | |
if (_envDTETask) | |
{ | |
using (new MessageFilter()) | |
{ | |
_taskFunction(taskContext); | |
} | |
} | |
else | |
{ | |
_taskFunction(taskContext); | |
} | |
lock (_objlock) | |
{ | |
if (!taskContext.Cancelled) | |
{ | |
_taskContext = null; | |
_startTime = 0; | |
} | |
} | |
} | |
} | |
public void Cancel() | |
{ | |
lock (_objlock) | |
{ | |
if (_taskContext != null) | |
{ | |
_taskContext.Cancel(); | |
_taskContext = null; | |
_startTime = 0; | |
} | |
} | |
} | |
public void Dispose() | |
{ | |
_wakeEvent.Dispose(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | |
[Guid("00000016-0000-0000-C000-000000000046")] | |
[ComImport] | |
public interface IOleMessageFilter | |
{ | |
[PreserveSig] | |
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo); | |
[PreserveSig] | |
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType); | |
[PreserveSig] | |
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[SuppressMessage("Style", "IDE1006", Justification = "<Pending>")] | |
public class MessageFilter : MarshalByRefObject, IDisposable, IOleMessageFilter | |
{ | |
private const int HANDLED = 0, RETRYALLOWED = 2, RETRY = 150, CANCEL = -1, WAITANDDISPATCH = 2; | |
private readonly IOleMessageFilter _oldFilter; | |
[DllImport("ole32.dll")] | |
private static extern int CoRegisterMessageFilter(IOleMessageFilter lpMessageFilter, out IOleMessageFilter lplpMessageFilter); | |
public MessageFilter() | |
{ | |
CoRegisterMessageFilter(this, out _oldFilter); | |
} | |
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr threadIdCaller, int dwTickCount, IntPtr lpInterfaceInfo) | |
{ | |
return HANDLED; | |
} | |
int IOleMessageFilter.RetryRejectedCall(IntPtr threadIDCallee, int dwTickCount, int dwRejectType) | |
{ | |
return dwRejectType == RETRYALLOWED ? RETRY : CANCEL; | |
} | |
int IOleMessageFilter.MessagePending(IntPtr threadIDCallee, int dwTickCount, int dwPendingType) | |
{ | |
return WAITANDDISPATCH; | |
} | |
public void Dispose() | |
{ | |
CoRegisterMessageFilter(_oldFilter, out var _); | |
GC.SuppressFinalize(this); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class TaskContext | |
{ | |
private volatile bool _cancelled; | |
public object Arg { get; } | |
public bool Cancelled => _cancelled; | |
public TaskContext() | |
{ | |
} | |
public TaskContext(object arg) | |
{ | |
Arg = arg; | |
} | |
public void Cancel() | |
{ | |
_cancelled = true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment