raymai97
raymai97

Reputation: 807

TaskScheduler RegisterTaskDefinition fails with NULL path in Win10

According to this MSDN doc, we may pass NULL for the path argument:

path [in] The name of the task. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value created by the Task Scheduler service.

I have a code that use this behavior. The code works fine in Win7 and 8.1, but not in my Win10 box (ver 1709 64-bit, build 16299). In Win10, it will return 0x80070005 aka "Access Denied" when path is NULL. If I specify a name like "Foobar", it will work fine.

Test code:

// Link comsuppw.lib and taskschd.lib.
#include <stdio.h>
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <shlobj.h>
#include <taskschd.h>
#include <comutil.h>

class AutoHR {
    HRESULT hr;
public:
    void operator=(HRESULT hr)
    {
        this->hr = hr;
        if (FAILED(hr)) {throw *this;}
    }
    HRESULT GetHR() const { return hr; }
};

static void TestTaskSched()
{
    AutoHR hr;
    CComPtr<ITaskService> taskSvc;
    CComPtr<ITaskFolder> taskFol;
    CComPtr<ITaskDefinition> taskDef;
    CComPtr<IActionCollection> taskAC;
    CComPtr<IAction> taskAction;
    CComPtr<IExecAction> taskEA;
    CComPtr<IRegisteredTask> registeredTask;
    try {
        hr = taskSvc.CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_ALL);
        hr = taskSvc->Connect(CComVariant(),CComVariant(),CComVariant(),CComVariant());
        hr = taskSvc->GetFolder(_bstr_t(L""), &taskFol); 
        hr = taskSvc->NewTask(0, &taskDef);
        hr = taskDef->get_Actions(&taskAC);
        hr = taskAC->Create(TASK_ACTION_EXEC, &taskAction);
        hr = taskAction.QueryInterface<IExecAction>(&taskEA);
        hr = taskEA->put_Path(_bstr_t(L"C:\\Windows\\System32\\cmd.exe"));
        hr = taskEA->put_Arguments(_bstr_t(L"/k echo Testing"));
        // Note that NULL is passed as the first argument.
        hr = taskFol->RegisterTaskDefinition(nullptr, taskDef,
            TASK_CREATE_OR_UPDATE, CComVariant(), CComVariant(),
            TASK_LOGON_NONE, CComVariant(), &registeredTask);
        MessageBoxW(nullptr, L"Succeeded!", L"OK", MB_ICONINFORMATION);
    }
    catch (AutoHR const &autohr) {
        WCHAR buf[99] = {0};
        wsprintfW(buf, L"HRESULT error 0x%.8X\n", autohr.GetHR());
        MessageBoxW(nullptr, buf, nullptr, MB_ICONERROR);
    }
}

int main()
{
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr))
    {
        TestTaskSched();
        CoUninitialize();
    }
    return 0;
}

Test result:

succeeded_and_failed_screenshot

Is there a behavior change between Win10 and older Windows? I suspect there is, but I cannot find any doc that mentions it.

I hope I don't have to generate GUID by myself for temporary task creation.

Upvotes: 1

Views: 542

Answers (0)

Related Questions