I'm trying to create a set of C# classes that I can schedule to run at a future time. The intention is to programmatically schedule these via other parts of my code.
This is the current class I'm trying to call via COM.
using System;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32.TaskScheduler;
namespace SchedulableTasks
{
[Guid("F5CAE94C-BCC7-4304-BEFB-FE1E5D56309A")]
public class TaskRegistry : ITaskHandler
{
private ITaskHandler _taskHandler;
public void Start(object pHandlerServices, string data)
{
var arguments = data.Split('|');
var taskTypeName = arguments.FirstOrDefault();
var taskArguments = arguments.Skip(1).FirstOrDefault();
var taskType = Type.GetType(taskTypeName);
_taskHandler = (ITaskHandler) Activator.CreateInstance(taskType);
_taskHandler.Start(pHandlerServices, taskArguments);
}
public void Stop(out int pRetCode)
{
var retCode = 1;
_taskHandler?.Stop(out retCode);
pRetCode = retCode;
}
public void Pause()
{
_taskHandler.Pause();
}
public void Resume()
{
_taskHandler.Resume();
}
}
}
Here's how I'm attempting to schedule the task
using System;
using Microsoft.Win32.TaskScheduler;
using Newtonsoft.Json;
using Action = Microsoft.Win32.TaskScheduler.Action;
namespace MyProject.Service
{
public static class SchedulingService
{
public enum ScheduledTask
{
BillingQuery
}
private static readonly Guid RegistryGUI = new Guid("F5CAE94C-BCC7-4304-BEFB-FE1E5D56309A");
public static void ScheduleAction(string name, string description, Trigger trigger, Action action)
{
using (var taskService = new TaskService())
{
var task = taskService.NewTask();
task.RegistrationInfo.Description = description;
task.Triggers.Add(trigger);
task.Actions.Add(action);
taskService.RootFolder.RegisterTaskDefinition(name, task);
}
}
public static Action CreateCSharpAction(ScheduledTask task, object data)
{
var taskData = $"{task.ToString()}|{JsonConvert.SerializeObject(data)}";
return new ComHandlerAction(RegistryGUI, taskData);
}
}
}
Microsoft.Win32.TaskScheduler
is version 2.7.2 of this library
I can create the scheduled task no problem, but when I attempt to run it, I get a Class not registered (0x80040154)
.
In my .csproj I'm registering the assembly as a COM object.
For the PlatformTarget
attribute, I've tried all of AnyCPU
, x86
, and x64
with the corresponding regasm.exe
.
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RegisterForComInterop>true</RegisterForComInterop>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
I'm using the following post-build event to register the .dll.
powershell C:\Windows\Microsoft.Net\Framework64\v4*\RegAsm.exe /codebase '$(ProjectDir)$(OutDir)SchedulableTasks.dll'
As near as I can tell, it's properly registered.
Procmon.exe seems to report the same. The thing I'm worried about is the "NAME NOT FOUND" for \TreatAs
, \InprocHandler
and \InprocServer32\InprocServer32
I think I see your problem:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Try targeting x86. Please see this answer for an in depth description: How to solve COM Exception Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))?
Edit:
I couldn't repro it, I added a few things:
[ComVisible(true)]