Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to register a COM object for usage in a scheduled task

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. Registry Screenshot

Procmon.exe seems to report the same. The thing I'm worried about is the "NAME NOT FOUND" for \TreatAs, \InprocHandler and \InprocServer32\InprocServer32 Procmon Screenshot

like image 845
Morgan Thrapp Avatar asked Nov 08 '22 13:11

Morgan Thrapp


1 Answers

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:

  1. The Attribute [ComVisible(true)]
  2. A Parameterless Constructor
  3. Signed the Assembly
  4. Had to run the powershell command once manually.

enter image description here

like image 95
Jeremy Thompson Avatar answered Nov 14 '22 22:11

Jeremy Thompson