How to use ActiveX component in ClassLibrary without Winforms - c#

How is it possible to use an ActiveX control in a ClassLibrary type project?
I intend to call it later from WPF application but I don't want to place a control anywhere on the form, so I don't want to use WindowsFormsHost; mainly because I would like to use this my library in Console App and Windows Service.
In this case, the ActiveX control I want to use is a video analysis component.
Additionally I want my component to register itself in deployed environment.

I think that the common knowledge is that you need Winforms to be able to use ActiveX control. Well, not entirely true. You need winforms-like message loop and STAThread.
Let's start by presenting the design of my solution. I prefer to seperate code to as many layers as needed when dealing with something unknown so you may find some layers redundant. I encourage you to help me improve the solution to find the equilibrium.
Please remember about the need to implement the IDisposable interface in all outer layers if needed.
ActiveXCore - class containing an ActiveX control declared as a private field. In this class you use just code like you would in Winforms.
CoreAPI - an internal API class that exposes the methods of ActiveXCore. I found out that it is good to mark the methods with [STAThreadAttribute] as I had some problems without it, though it may be specific to this case only.
PublicAPI - my main library class that will be called in the referencing projects.
Now, in the ActiveXCore there are really no guidelines.
In CoreAPI the sample method would be
[STAThreadAttribute]
internal bool Init()
{
try
{
_core = new ActiveXCore();
//...
return true;
}
catch (System.Runtime.InteropServices.COMException)
{
//handle the exception
}
return false;
}
To be able to properly run these you would need Winforms like message loop like this (the desing is not mine at all, I just slightly modified the code). You don't need the Winforms project type, but you have to reference System.Windows.Forms assembly
public class MessageLoopApartment : IDisposable
{
public static MessageLoopApartment Apartament
{
get
{
if (_apartament == null)
_apartament = new MessageLoopApartment();
return _apartament;
}
}
private static MessageLoopApartment _apartament;
private Thread _thread; // the STA thread
private TaskScheduler _taskScheduler; // the STA thread's task scheduler
public TaskScheduler TaskScheduler { get { return _taskScheduler; } }
/// <summary>MessageLoopApartment constructor</summary>
public MessageLoopApartment()
{
var tcs = new TaskCompletionSource<TaskScheduler>();
// start an STA thread and gets a task scheduler
_thread = new Thread(startArg =>
{
EventHandler idleHandler = null;
idleHandler = (s, e) =>
{
// handle Application.Idle just once
Application.Idle -= idleHandler;
// return the task scheduler
tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());
};
// handle Application.Idle just once
// to make sure we're inside the message loop
// and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
_thread.SetApartmentState(ApartmentState.STA);
_thread.IsBackground = true;
_thread.Start();
_taskScheduler = tcs.Task.Result;
}
/// <summary>shutdown the STA thread</summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_taskScheduler != null)
{
var taskScheduler = _taskScheduler;
_taskScheduler = null;
// execute Application.ExitThread() on the STA thread
Task.Factory.StartNew(
() => Application.ExitThread(),
CancellationToken.None,
TaskCreationOptions.None,
taskScheduler).Wait();
_thread.Join();
_thread = null;
}
}
/// <summary>Task.Factory.StartNew wrappers</summary>
public void Invoke(Action action)
{
Task.Factory.StartNew(action,
CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Wait();
}
public TResult Invoke<TResult>(Func<TResult> action)
{
return Task.Factory.StartNew(action,
CancellationToken.None, TaskCreationOptions.None, _taskScheduler).Result;
}
public Task Run(Action action, CancellationToken token)
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
}
public Task<TResult> Run<TResult>(Func<TResult> action, CancellationToken token)
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler);
}
public Task Run(Func<Task> action, CancellationToken token)
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
}
public Task<TResult> Run<TResult>(Func<Task<TResult>> action, CancellationToken token)
{
return Task.Factory.StartNew(action, token, TaskCreationOptions.None, _taskScheduler).Unwrap();
}
}
And then you can provide methods like that
public bool InitLib()
{
return MessageLoopApartment.Apartament.Run(() =>
{
ca = new CoreAPI();
bool initialized = ca.Init();
}, CancellationToken.None).Result;
}
of if the method would be void
public void InitLib()
{
MessageLoopApartment.Apartament.Run(() =>
{
ca = new CoreAPI();
ca.Init();
}, CancellationToken.None).Wait();
}
As for the auto registering I designed something like this (I call it from CoreAPI)
internal static class ComponentEnvironment
{
internal static void Prepare()
{
CopyFilesAndDeps();
if (Environment.Is64BitOperatingSystem)
RegSvr64();
RegSvr32(); //you may notice no "else" here
//in my case for 64 bit I had to copy and register files for both arch
}
#region unpack and clean files
private static void CopyFilesAndDeps()
{
//inspect what file you need
}
#endregion unpack and clean files
#region register components
private static void RegSvr32()
{
string dllPath = #"xxx\x86\xxx.dll";
Process.Start("regsvr32", "/s " + dllPath);
}
private static void RegSvr64()
{
string dllPath = #"xxx\x64\xxx.dll";
Process.Start("regsvr32", "/s " + dllPath);
}
#endregion register components
}
I spent many days and nights to design this reusable pattern so I hope it will help someone.

Related

TaskCompletionSource - code stop executing when disposing

I am using the library to manage WiFi. The library has a method to scan networks based on events.
I wrap this library with my code and I want to change events to the async pattern.
So my method looks like this:
public Task ScanNetworksAsync()
{
var tcs = new TaskCompletionSource<bool>();
void Callback(Wlan.WlanNotificationData data)
{
switch (data.notificationCode)
{
case (int) Wlan.WlanNotificationCodeAcm.ScanFail:
_wlanInterface!.WlanNotification -= Callback;
tcs.SetResult(false);
break;
case (int) Wlan.WlanNotificationCodeAcm.ScanComplete:
_wlanInterface!.WlanNotification -= Callback;
tcs.SetResult(true);
break;
}
}
_wlanInterface!.WlanNotification += Callback;
try
{
_wlanInterface!.Scan();
}
catch (Exception e)
{
tcs.SetException(e);
}
return tcs.Task;
}
Important is it that implement Dispose method where I dispose internal client.
public void Dispose() => ((IDisposable) _internalClient).Dispose();
Place where I use my class:
internal class Program
{
private static IContainer? _container;
private static async Task Main(string[] args)
{
_container = new Startup().BuildContainer();
await using (var scope = _container!.BeginLifetimeScope())
{
var s = scope.Resolve<IWiFiClient>();
await s.ScanNetworksAsync();
}
SubscribeEvents();
}
}
And here I have a problem. Method SubscriveEvents never call.
When I change
await s.ScanNetworkAsync();
to
s.ScanNetworkAsync().GetWaiter().GetResult();
then everything works but I don't know why.
And everything all works when I use await but not implement dispose method.
I don't understand it because the task is completed before disposing scope, so why code is hanging?

API methods must wait until critical method is done

I have MVC API controller.
One method in this controller is critical.
This mean that all other API methods must wait util this method is done.
My basic idea is to block threads in constructor.
But I am not sure if this is so smart?
public class TestApi : Controller
{
private static bool wait = false;
public TestApi()
{
// wait if critical method is working.
while (wait)
{
System.Threading.Thread.Sleep(100);
}
}
[HttpPost]
public void PostCriticalMethod()
{
try
{
wait = true;
// do critical work
}
finally
{
wait = false;
}
}
// Many non critical API methods...
}
Solution two:
public class TestApi : Controller
{
private static bool wait = false;
private static AutoResetEvent waitHandle = new AutoResetEvent(false);
public TestApi()
{
// wait if critical method is working.
if (wait) waitHandle.WaitOne();
}
[HttpPost]
public void PostCriticalMethod()
{
try
{
wait = true;
// do critical work
}
finally {
waitHandle.Set();
wait = false;
}
}
// Many non critical API methods...
}
My solution (This is async version, but non async is even simpler):
In base class (common for all controllers) I add method BlockOtherRequestsBeforeExecute
private static readonly SemaphoreSlim semaphoreInit = new SemaphoreSlim(1, 1);
protected async Task BlockOtherRequestsBeforeExecute(Func<Task> criticalAction)
{
await semaphoreInit.WaitAsync();
try
{
await criticalAction();
}
finally
{
semaphoreInit.Release();
}
}
Then I can call method in secure way if I need to:
await BlockOtherRequestsBeforeExecute(async () => await RestoreDatabase());
Important part is that semaphoreInit must be used in all critical places.
This can be done in constructor of base class, and then all API-s are blocked until critical action is not finished.

.NET TaskScheduler, async/await, ensuring that Tasks never run longer than a certain period of time

I am writing a WPF project, using C# 5 and async/await.
I'd like to, during development, add some code that will alert the developer any task takes longer than a certain period of time. This will ensure that the developer never accidentally does file/network IO on the UI thread, as well as any other long running computations that should be moved to another thread.
Is there somewhere to override the TaskScheduler, to wrap each Task with the following?
private Task WrapTask(Task task)
{
return Task.Run(async () =>
{
var stopwatch = new Stopwatch();
stopwatch.Start();
await task;
stopwatch.Stop();
if (stopwatch.Elapsed > TimeSpan.FromMilliseconds(5))
{
// TODO: Log
Debug.WriteLine("A task took longer than expected.");
}
});
}
This should be transparent to the user, and also should be used when in the context of an async/await method.
THIS DOESN'T WORK AT ALL, JUST TO ILLUSTRATE: Maybe wrapping a TaskScheduler like this, and then someone replacing the current one?
public class TaskSchedulerTimer : TaskScheduler
{
private readonly TaskScheduler _taskScheduler;
private readonly MethodInfo _queueTaskMethod;
private readonly MethodInfo _tryExecuteTaskInlineMethod;
private readonly MethodInfo _getScheduledTasksMethod;
public TaskSchedulerTimer(TaskScheduler taskScheduler)
{
_taskScheduler = taskScheduler;
_queueTaskMethod = typeof(TaskScheduler).GetMethod("QueueTask");
_tryExecuteTaskInlineMethod = typeof(TaskScheduler).GetMethod("TryExecuteTaskInline");
_getScheduledTasksMethod = typeof(TaskScheduler).GetMethod("GetScheduledTasks");
}
protected override void QueueTask(Task task)
{
_queueTaskMethod.Invoke(_taskScheduler, new object[] { WrapTask(task) });
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return (bool)_tryExecuteTaskInlineMethod.Invoke(_taskScheduler, new object[] { WrapTask(task), taskWasPreviouslyQueued });
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return (IEnumerable<Task>)_getScheduledTasksMethod.Invoke(_taskScheduler, new object[] { });
}
private Task WrapTask(Task task)
{
return Task.Run(async () =>
{
var stopwatch = new Stopwatch();
stopwatch.Start();
await task;
stopwatch.Stop();
if (stopwatch.Elapsed > TimeSpan.FromMilliseconds(5))
{
// TODO: Log
Debug.WriteLine("A task took longer than expected.");
}
});
}
}
Maybe I need to go lower, to the SynchronizationContext, and do something similar there?
UPDATE: It seems that the current TaskScheduler used in WPF wraps around the Dispatcher. There appears to be some hooks on there, so I am covered for my purposes. However, I'd still like to know if my original question has a good answer.
FYI, here is my code for the timing stuff, in WPF.
private readonly Stopwatch _currentOperation = new Stopwatch();
Dispatcher.Hooks.OperationStarted += HooksOnOperationStarted;
Dispatcher.Hooks.OperationCompleted += HooksOnOperationCompleted;
Dispatcher.Hooks.OperationAborted += HooksOnOperationAborted;
private void HooksOnOperationStarted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
_currentOperation.Start();
}
private void HooksOnOperationCompleted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
_currentOperation.Stop();
if (_currentOperation.Elapsed > TimeSpan.FromMilliseconds(5))
{
// TODO: Log
Debug.WriteLine("A task took longer than expected.");
}
_currentOperation.Reset();
}
private void HooksOnOperationAborted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs)
{
Debug.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId);
_currentOperation.Stop();
if (_currentOperation.Elapsed > TimeSpan.FromMilliseconds(5))
{
// TODO: Log
Debug.WriteLine("A task took longer than expected.");
}
_currentOperation.Reset();
}

Make the TaskScheduler synchronously and run in the main thread

I'm looking for a way to create a TaskScheduler that runs synchronously in the main thread to allow WPF applications to be configured as single thread for debugging purpose.
Any idea?
For now I'm using the sample LimitedTaskScheduler on MSDN that allow to specify the concurrency level (how many threads use) and this extension to set the static TaskFactory before the application starts:
void SetOnTaskFactory(TaskFactory taskFactory)
{
const BindingFlag = BindingFlags.Static | BindingFlags.NonPublic
var field = typeof(Task).GetField("s_factory", BindingFlag);
field.SetValue(null, taskFactory);
}
For testing purposes you can use the CurrentThreadTaskScheduler from ParallelExtensionsExtras library.
Basically it's a simple TaskScheduler that executes all tasks on the current thread.
If you want to create a SynchronousTaskScheduler, you can do so using below code.
void Main()
{
SynchronousTaskScheduler taskScheduler = new SynchronousTaskScheduler();
for (int i = 0; i < 100; i++)
{
Task.Factory.StartNew(() => SomeMethod(i), CancellationToken.None, TaskCreationOptions.None, taskScheduler);
}
}
void SomeMethod(int number)
{
$"Scheduled task {number}".Dump();
}
// Define other methods and classes here
class SynchronousTaskScheduler : TaskScheduler
{
public override int MaximumConcurrencyLevel
{
get { return 1; }
}
protected override void QueueTask(Task task)
{
TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(
Task task,
bool taskWasPreviouslyQueued)
{
return TryExecuteTask(task);
}
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
}

Write an Async method that will await a bool

I would like to write a method that will await for a variable to be set to true.
Here is the psudo code.
bool IsSomethingLoading = false
SomeData TheData;
public async Task<SomeData> GetTheData()
{
await IsSomethingLoading == true;
return TheData;
}
TheData will be set by a Prism Event along with the IsSomethingLoading variable.
I have a call to the GetTheData method, but I would like it to run async (right now it just returns null if the data is not ready. (That leads to other problems.)
Is there a way to do this?
In many situations like this what you need is a TaskCompletionSource.
You likely have a method that is able to generate the data at some point in time, but it doesn't use a task to do it. Perhaps there is a method that takes a callback which provides the result, or an event that is fired to indicate that there is a result, or simply code using a Thread or ThreadPool that you are not inclined to re-factor into using Task.Run.
public Task<SomeData> GetTheData()
{
TaskCompletionSource<SomeData> tcs = new TaskCompletionSource<SomeData>();
SomeObject worker = new SomeObject();
worker.WorkCompleted += result => tcs.SetResult(result);
worker.DoWork();
return tcs.Task;
}
While you may need/want to provide the TaskCompletionSource to the worker, or some other class, or in some other way expose it to a broader scope, I've found it's often not needed, even though it's a very powerful option when it's appropriate.
It's also possible that you can use Task.FromAsync to create a task based on an asynchronous operation and then either return that task directly, or await it in your code.
You could use a TaskCompletionSource as your signal, and await that:
TaskCompletionSource<bool> IsSomethingLoading = new TaskCompletionSource<bool>();
SomeData TheData;
public async Task<SomeData> GetTheData()
{
await IsSomethingLoading.Task;
return TheData;
}
And in your Prism event do:
IsSomethingLoading.SetResult(true);
This work for me:
while (IsLoading) await Task.Delay(100);
I propose a very simple solution but not the best to answer the original question, if you are not regarding at speed performance :
...
public volatile bool IsSomethingLoading = false;
...
public async Task<SomeData> GetTheData()
{
// Launch the task asynchronously without waiting the end
_ = Task.Factory.StartNew(() =>
{
// Get the data from elsewhere ...
});
// Wait the flag
await Task.Factory.StartNew(() =>
{
while (IsSomethingLoading)
{
Thread.Sleep(100);
}
});
return TheData;
}
Important note : #Theodor Zoulias proposed : IsSomethingLoading shall be declared with volatile keyword, to avoid compiler optimizations and potential multithread issues when accessing from other threads.
For further information about compilator omptimizations follow this article :
The C# Memory Model in Theory and Practice
I'm adding a full test code below :
XAML :
<Label x:Name="label1" Content="Label" HorizontalAlignment="Left" Margin="111,93,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2" Height="48" Width="312"/>
Test Code :
public partial class MainWindow : Window
{
// volatile keyword shall be used to avoid compiler optimizations
// and potential multithread issues when accessing IsSomethingLoading
// from other threads.
private volatile bool IsSomethingLoading = false;
public MainWindow()
{
InitializeComponent();
_ = TestASyncTask();
}
private async Task<bool> TestASyncTask()
{
IsSomethingLoading = true;
label1.Content = "Doing background task";
// Launch the task asynchronously without waiting the end
_ = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
IsSomethingLoading = false;
Thread.Sleep(5000);
HostController.Host.Invoke(new Action(() => label1.Content = "Background task terminated"));
});
label1.Content = "Waiting IsSomethingLoading ...";
// Wait the flag
await Task.Run(async () => { while (IsSomethingLoading) { await Task.Delay(100); }});
label1.Content = "Wait Finished";
return true;
}
}
/// <summary>
/// Main UI thread host controller dispatcher
/// </summary>
public static class HostController
{
/// <summary>
/// Main Host
/// </summary>
private static Dispatcher _host;
public static Dispatcher Host
{
get
{
if (_host == null)
{
if (Application.Current != null)
_host = Application.Current.Dispatcher;
else
_host = Dispatcher.CurrentDispatcher;
}
return _host;
}
}
}

Categories

Resources