使用Win32 API 1.0创建任务不显示于任务计划程序GUI且保存失败
问题描述
- 运行微软文档中的任务创建示例程序,生成了
C:\Windows\Tasks下的.job文件,但任务计划程序GUI中无法看到该任务,怀疑是使用了Task Scheduler 1.0接口导致。 - 后续在示例基础上添加
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON标志,并调用SetAccountInformation设置账户信息,现在保存任务失败,错误信息:(任务XML包含意外节点) : 保存任务失败,错误码 = 0x80041316
附上代码:
void stringError(HRESULT hr) { _com_error err(hr); LPCTSTR errMsg = err.ErrorMessage(); fprintf(stderr, "错误信息 (%ls) : ", errMsg); } int main() { HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "初始化COM库失败,错误码 = 0x%x\n", hr); return 1; } ITaskScheduler* pITS = NULL; hr = CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pITS); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "创建任务计划程序实例失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } LPCWSTR pwszTaskName = L"SampleTask"; ITask* pITask = NULL; IPersistFile* pIPersistFile = NULL; hr = pITS->NewWorkItem(pwszTaskName, CLSID_CTask, IID_ITask, (IUnknown**)&pITask); if (FAILED(hr)) { if (hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)) { fprintf(stderr, "任务已存在,尝试删除...\n"); hr = pITS->Delete(pwszTaskName); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "删除现有任务失败,错误码 = 0x%x\n", hr); pITS->Release(); CoUninitialize(); return 1; } hr = pITS->NewWorkItem(pwszTaskName, CLSID_CTask, IID_ITask, (IUnknown**)&pITask); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "删除后创建新任务失败,错误码 = 0x%x\n", hr); pITS->Release(); CoUninitialize(); return 1; } } else { stringError(hr); fprintf(stderr, "创建新任务失败,错误码 = 0x%x\n", hr); pITS->Release(); CoUninitialize(); return 1; } } pITS->Release(); hr = pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "设置任务标志失败,错误码 = 0x%x\n", hr); pITask->Release(); CoUninitialize(); return 1; } hr = pITask->SetAccountInformation(L"", NULL); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "设置账户信息失败,错误码 = 0x%x\n", hr); pITask->Release(); CoUninitialize(); return 1; } hr = pITask->QueryInterface(IID_IPersistFile, (void**)&pIPersistFile); pITask->Release(); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "查询IPersistFile接口失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } hr = pIPersistFile->Save(NULL, TRUE); pIPersistFile->Release(); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "保存任务失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } CoUninitialize(); printf("任务创建成功。\n"); return 0; }
解决方案
问题根源:你使用的是Task Scheduler 1.0旧接口(
CLSID_CTaskScheduler/ITask),该接口生成的是传统.job格式任务,不会在现代任务计划程序GUI中显示;而0x80041316错误是因为新版Windows系统对旧任务的XML格式兼容性限制,导致保存失败。解决办法:改用Task Scheduler 2.0接口(Windows Vista及以上系统支持),使用
ITaskService、ITaskDefinition等新接口创建任务,生成的任务会正常显示在GUI中,且不会出现XML节点错误。修复后的代码示例:
#include <windows.h> #include <taskschd.h> #include <comdef.h> #include <stdio.h> #pragma comment(lib, "taskschd.lib") #pragma comment(lib, "comsupp.lib") void stringError(HRESULT hr) { _com_error err(hr); LPCTSTR errMsg = err.ErrorMessage(); fprintf(stderr, "错误信息 (%ls) : ", errMsg); } int main() { HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "初始化COM库失败,错误码 = 0x%x\n", hr); return 1; } ITaskService* pTaskService = NULL; hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pTaskService); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "创建任务计划程序服务实例失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } hr = pTaskService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "连接任务计划程序服务失败,错误码 = 0x%x\n", hr); pTaskService->Release(); CoUninitialize(); return 1; } ITaskFolder* pRootFolder = NULL; hr = pTaskService->GetFolder(_bstr_t(L"\\"), &pRootFolder); pTaskService->Release(); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "获取根任务文件夹失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } // 检查任务是否存在,存在则删除 VARIANT_BOOL taskExists = VARIANT_FALSE; hr = pRootFolder->Exists(_bstr_t(L"SampleTask"), &taskExists); if (SUCCEEDED(hr) && taskExists) { fprintf(stderr, "任务已存在,尝试删除...\n"); hr = pRootFolder->DeleteTask(_bstr_t(L"SampleTask"), 0); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "删除现有任务失败,错误码 = 0x%x\n", hr); pRootFolder->Release(); CoUninitialize(); return 1; } } ITaskDefinition* pTaskDef = NULL; hr = pRootFolder->NewTask(0, &pTaskDef); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "创建任务定义失败,错误码 = 0x%x\n", hr); pRootFolder->Release(); CoUninitialize(); return 1; } // 设置任务设置 ITaskSettings* pSettings = NULL; hr = pTaskDef->get_Settings(&pSettings); if (SUCCEEDED(hr)) { pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); pSettings->put_RunOnlyIfLoggedOn(VARIANT_TRUE); // 对应TASK_FLAG_RUN_ONLY_IF_LOGGED_ON pSettings->Release(); } // 设置触发器(这里设置为启动时触发,可根据需求修改) ITriggerCollection* pTriggerCollection = NULL; hr = pTaskDef->get_Triggers(&pTriggerCollection); if (SUCCEEDED(hr)) { ITrigger* pTrigger = NULL; hr = pTriggerCollection->Create(TASK_TRIGGER_BOOT, &pTrigger); if (SUCCEEDED(hr)) { pTrigger->Release(); } pTriggerCollection->Release(); } // 设置操作(这里设置为运行notepad.exe,可根据需求修改) IActionCollection* pActionCollection = NULL; hr = pTaskDef->get_Actions(&pActionCollection); if (SUCCEEDED(hr)) { IAction* pAction = NULL; hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); if (SUCCEEDED(hr)) { IExecAction* pExecAction = NULL; hr = pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction); if (SUCCEEDED(hr)) { pExecAction->put_Path(_bstr_t(L"C:\\Windows\\notepad.exe")); pExecAction->Release(); } pAction->Release(); } pActionCollection->Release(); } // 注册任务 IRegisteredTask* pRegisteredTask = NULL; hr = pRootFolder->RegisterTaskDefinition( _bstr_t(L"SampleTask"), pTaskDef, TASK_CREATE_OR_UPDATE, _variant_t(), // 当前用户 _variant_t(), TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(L""), &pRegisteredTask ); pTaskDef->Release(); pRootFolder->Release(); if (FAILED(hr)) { stringError(hr); fprintf(stderr, "注册任务失败,错误码 = 0x%x\n", hr); CoUninitialize(); return 1; } printf("任务创建成功,可在任务计划程序GUI中查看。\n"); pRegisteredTask->Release(); CoUninitialize(); return 0; }
内容的提问来源于stack exchange,提问作者NImIPKZvUc
相关产品推荐
相关产品推荐

