2017-01-31 8 views
0

Я работаю над проектом, которому необходимо установить ряд задач планировщика задач Windows, и для этого я создал проект Wix и пользовательское действие, которое заботится обо всех деталях. Это пользовательское действие было создано с использованием C++, чтобы избежать зависимостей от .NET Framework.TaskScheduler ExecAction put_WorkingDirectory не обновляет свое значение

Сначала я начал выполнять SCHTASKS.EXE из пользовательского действия Wix, но после того, как мне удалось создать правильную командную строку для правильной установки задачи, я понял, что не могу установить Рабочий каталог Action («Начать в», в пользовательском интерфейсе планировщика заданий) из командной строки SCHTASKS.EXE, потому что у него просто не было опции ...

Я решил затем использовать COM в C++ (#import <taskschd.dll> raw_interfaces_only), чтобы добраться до планировщика заданий и настроить WorkFolder, используя API, после установки задачи с использованием SCHTASKS.EXE, который отлично работал с этой деталью. Мне удалось добраться до задачи и прочитать ее значения после правильной установки задачи, но когда я выполнил метод put_WorkingDirectory с текущим значением, которое действительно не сработало, но значение не было сохранено в задаче.

У кого-нибудь есть ключ, почему я не мог туда добраться? Это часть кода, который я использовал для доступа к ExecAction, и установил значение успешно. Помните, что это выполняется в пользовательском действии Wix, поэтому некоторые вызовы методов - это Wix.

Этот код фактически работает, и в журнале отображается правильный путь, который я намереваюсь установить, но задача не изменяется. Что я делаю не так?

HRESULT UpdateWorkingDirectory(TaskScheduler::ITaskFolderPtr rootFolder, BSTR taskName, BSTR installFolder) 
{ 
    HRESULT          hr   = S_OK; 
    TaskScheduler::IRegisteredTaskCollectionPtr taskCollection; 
    LONG          numTasks = 0; 
    TaskScheduler::IRegisteredTaskPtr   thisTask; 
    TaskScheduler::ITaskDefinitionPtr   definition; 
    TaskScheduler::IActionCollectionPtr   actions; 
    TaskScheduler::IActionPtr     action; 
    TaskScheduler::IExecActionPtr    execAction; 
    long          actionCount; 

    hr = rootFolder->GetTasks(NULL, &taskCollection); 
    ExitOnFailure(hr, "Cannot get task collection pointer"); 

    hr = taskCollection->get_Count(&numTasks); 
    ExitOnFailure(hr, "Cannot get task collection item count"); 

    for (LONG taskIdx = 0; taskIdx < numTasks; taskIdx++) { 
     TaskScheduler::IRegisteredTaskPtr registeredTask; 
     bstr_t        taskIdxName; 

     hr = taskCollection->get_Item(variant_t(taskIdx + 1), &registeredTask); 
     ExitOnFailure(hr, "Cannot get task item %d", taskIdx + 1); 

     hr = registeredTask->get_Name(&taskIdxName.GetBSTR()); 
     ExitOnFailure(hr, "Cannot get task name"); 
     WcaLog(LOGMSG_STANDARD, " registered task name = %s", (LPCSTR)taskIdxName); 

     if (strcmp(bstr_t(taskName), taskIdxName) == 0) { 
      thisTask = registeredTask; 
      break; 
     } 
    } 
    if (thisTask == NULL) { 
     hr = E_FAIL; 
     ExitOnFailure(hr, "task {%S} not found", taskName); 
    } 

    hr = thisTask->get_Definition(&definition); 
    ExitOnFailure(hr, "error getting task definition for {%S}", taskName); 

    hr = definition->get_Actions(&actions); 
    ExitOnFailure(hr, "error getting actions for {%S}", taskName); 
    WcaLog(LOGMSG_STANDARD, " got actions from %S", taskName); 

    hr = actions->get_Count(&actionCount); 
    ExitOnFailure(hr, "error getting action count for {%S}", taskName); 
    WcaLog(LOGMSG_STANDARD, " got count = %d from {%S}", actionCount, taskName); 

    if (actionCount > 0) { 
     bstr_t actionId; 
     bstr_t arguments; 
     bstr_t path; 

     hr = actions->get_Item(1, &action); 
     ExitOnFailure(hr, "error getting action[1] for {%S}", taskName); 

     hr = action->QueryInterface(&execAction); 
     ExitOnFailure(hr, "error getting ExecAction for {%S}", taskName); 

     hr = execAction->get_Id(&actionId.GetBSTR()); 
     ExitOnFailure(hr, "error getting Exec Action id for first exec action of {%S}", taskName); 
     WcaLog(LOGMSG_STANDARD, " first Exec Action Id is %s", (LPCSTR)actionId); 

     hr = execAction->get_Arguments(&arguments.GetBSTR()); 
     ExitOnFailure(hr, "error getting Exec Action arguments for first exec action of {%S}", taskName); 
     WcaLog(LOGMSG_STANDARD, " first Exec Action arguments are %s", (LPCSTR)arguments); 

     hr = execAction->get_Path(&path.GetBSTR()); 
     ExitOnFailure(hr, "error getting Exec Action path for first exec action of {%S}", taskName); 
     WcaLog(LOGMSG_STANDARD, " first Exec Action path is %s", (LPCSTR)path); 

     hr = execAction->put_WorkingDirectory(installFolder); 
     ExitOnFailure(hr, "error putting working directory for {%S}", taskName); 
     WcaLog(LOGMSG_STANDARD, " successful put working directory to %S", installFolder); 
    } 

LExit: 
    return hr; 
} 

ПРИМЕЧАНИЕ: Все C++ образцы, которые я нашел используется простой интерфейс указателей вместо смарт-указатели, я предпочел смарт-указатели, чтобы избежать заботиться об освобождении от себя

ответ

0

Я нашел ответ

я должен был изменить сигнатуру методы для размещения имени пользователя и пароля

HRESULT UpdateWorkingDirectory(TaskScheduler::ITaskFolderPtr rootFolder, BSTR taskName, BSTR installFolder, variant_t username, variant_t password) 

и добавить эти пять линий

 thisTask = NULL; 

     hr = rootFolder->RegisterTaskDefinition(taskName, definition, TaskScheduler::_TASK_CREATION::TASK_UPDATE, username, password, TaskScheduler::_TASK_LOGON_TYPE::TASK_LOGON_PASSWORD, variant_t(), &thisTask); 
     ExitOnFailure(hr, "error updating task regisration for {%S}", taskName); 
     WcaLog(LOGMSG_STANDARD, " successful update of task regisration to %S", taskName); 

после выполнения put_WorkingDirectory.

Это обновляет регистрацию определения задачи с обновленным значением, это то, что я хотел сделать, и это сработало !!!!

0

Мне кажется, что это хороший пример:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa446854(v=vs.85).aspx

Более конкретно, это показывает, что вы называете ITask :: Активизировать перед изменением вещи, как рабочий каталог, и что вы называете IPersistFile, чтобы сохранить изменения. Я не вижу ни одного из этих примеров. Я не смотрел на эти интерфейсы некоторое время, но это может быть проблемой.

+0

Это для TaskScheduler 1.0, и я хочу установить его в версии 2.0. Новая версия имеет более сложную иерархию объектов, и на этом уровне у нее нет метода SetWorkingDirectory. В любом случае, спасибо –