I schedule my application in the task scheduler using the ITask class incorporated with the winapi.
I have this piece of code: dwTask->SetAccountInformation(L"", NULL);
The first parameter requires the username of the user to run the task.
By setting it to blank it runs the task as a NTAUTHORITY/SYSTEM service and therefore I run into spikes in the system where when I run commands in that task it doesnt appear on the screen (I want to fix this, as I'd like to keep NTAUTHORITY/SYSTEM privileges with my application -> see my last question: Task Scheduler WorkItem Not Running)
The question for this post is; How can I set the first parameter to the current user that is logged in? I tried to use GetUserName but the first parameter is a WIDE CHAR array data type. I tried to use GetUserNameW but the program still failed to compile due to unknown errors. Has anyone been able to set their scheduled task as the current user? Thanks!
EDIT
Okay! I added the GetUserNameW as suggested into my code. Then I linked it to the first parameter of SetAccountInformation. There are no errors compile time. After I run the program by double clicking it, it doesnt add the process as a task. Clearly it didn't work. Here is the code that I am using...
static bool AddProcessAsTask()
{
LPWSTR uname=L"";
DWORD size = 1024;
ITask *pITask;
HRESULT hr = S_OK;
LPCWSTR pwszTaskName;
ITaskScheduler *pITS;
LPCWSTR pwszApplicationName;
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance
(
CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}
}
else
{
return FALSE;
}
pwszTaskName = L"AV_Updater Watchdog";
hr = pITS->NewWorkItem
(
pwszTaskName,
CLSID_CTask,
IID_ITask,
(IUnknown**)&pITask
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}
pwszApplicationName = L"C:\\Windows\\watchdog.exe";
hr = pITask->SetApplicationName(pwszApplicationName);
if (FAILED(hr))
{
pITS->Release();
pITask->Release();
CoUninitialize();
return FALSE;
}
GetUserNameW(uname, &size);
pITask->SetAccountInformation(uname, NULL);
pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
pITS->AddWorkItem(pwszTaskName, pITask);
pITS->Release();
hr = pITask->Run();
if (FAILED(hr))
{
pITask->Release();
CoUninitialize();
return FALSE;
}
pITask->Release();
CoUninitialize();
return TRUE;
}
Related
I was referring to the example program provided here to run a video file, in my case mp4 format using DShow.
Refer to the complete code:
#include <dshow.h>
#pragma comment (lib, "strmiids.lib")
void main(void)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Build the graph. IMPORTANT: Change this string to a file on your system.
hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
}
However when I build the program, the build is sucessful but when I run it, the console window pops up and disappears within a second.
I referred to the comments on the same page and many others faced the same issue. However a few were able to successfully run the program.
What is it that I am doing wrong?
Is it the type of project I am selecting? I am selecting win32 console application. Should I select something else? Or is there something else that I am doing wrong?
1,I'd like to show 9 videos at same time.
2,I have a main thread which create all the windows and handle the WM_* message, also in charge of: A), init vmrvideorender9, MediaControl B), connect filter C), stop and release the MediaControl. and other things.
3,For every video, there is also a render thread which is for sample delivering.
Now, I have many deadlock, they hang at different place and CPU is very high.
The deadlock most happens when resizing the windows.
for example: when I call the following function, sometimes it can consume 40 seconds and sometimes it just hang inside the function.
Void GetVMR9VideoRender()
{
hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (LPVOID *)&pRender.p);
if (FAILED(hr))
{
return NULL;
}
CComPtr <IVMRFilterConfig9> pConfig;
hr =pRender->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
if (FAILED(hr))
return NULL;
pConfig->SetRenderingMode(VMRMode_Windowless);
pConfig->SetNumberOfStreams(1);
CComPtr<IVMRWindowlessControl9> lpDefWC;
hr = pRender->QueryInterface(IID_IVMRWindowlessControl9, (LPVOID*)&lpDefWC.p);
if (FAILED(hr))
{
return NULL;
}
m_lpDefWC = (IVMRWindowlessControl*)lpDefWC.p ;
CComPtr<IVMRAspectRatioControl9> lpARC;
hr = pRender->QueryInterface(IID_IVMRWindowlessControl9, (LPVOID*)&lpARC.p);
if (FAILED(hr))
{
return NULL;
}
m_lpARC = (IVMRAspectRatioControl*)lpARC.p ;
return pRender;
}
I am trying to write a windows Logon trigger task using C++ on Windows 7.
I am following this microsoft tutorial.
But I am facing problem in saving the task to root folder.
Here:
// ------------------------------------------------------
// Save the task in the root folder.
IRegisteredTask *pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(
_bstr_t( wszTaskName ),
pTask,
TASK_CREATE_OR_UPDATE,
_variant_t(L"Builtin\\Administrators"),
_variant_t(),
TASK_LOGON_GROUP,
_variant_t(L""),
&pRegisteredTask);
Where the hr is getting error : No Mapping between account names and security ids was done
I also tried replacing _variant_t(L"Builtin\\Administrators") with _variant_t(L"S-1-5-32-544") to NULL out language hard coding issue, still No luck.
How can I make it work?
A definitive solution to creation of a TaskScheduler task on Windows startup
(with Administor privileges, working for Windows 7, 8, etc. Note that this won't display an UAC popup on Windows startup "Are you sure to run this software with Admin rights?", that's why the TaskScheduler method is more interesting in this case than the good old HKEY_LOCAL_MACHINE\...\CurrentVersion\Run solution)
There are a few things to update in this tutorial
to make it work:
_variant_t(L"S-1-5-32-544") instead of _variant_t(L"Builtin\\Administrators")
_CRT_SECURE_NO_WARNINGS
In VC++, Project Properties > Configuration Properties > Linker > Manifest file > UAC Execution Level > requireAdministrator
Remove the date boundaries which are now outdated !
Replace hr = pLogonTrigger->put_UserId(_bstr_t(L"DOMAIN\\UserName")); by either a hardcoded Domain\Username, or by some Domain\Username detection code (I couldn't make it work), or just comment this line, it worked for me!
Add some code for TASK_RUNLEVEL_HIGHEST
Add some code to enable the task even if running from a laptop on batteries (default would be "don't run task if on batteries"!), and some code to prevent the .exe to be killed after some time (By default, a task will be stopped 72 hours after it starts to run), etc.
Then you'll get the famous:
Success! Task successfully registered.
Phew! After a few hours per day and some edits, now here is a working full main.cpp:
#define SECURITY_WIN32
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
#include <Security.h>
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
using namespace std;
#define TASKNAME L"Logon Trigger Test Task"
int __cdecl wmain()
{
// Get the windows directory and set the path to notepad.exe.
wstring wstrExecutablePath = _wgetenv(L"WINDIR");
wstrExecutablePath += L"\\SYSTEM32\\NOTEPAD.EXE";
// Initialize COM
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr)) return 1;
// Set general COM security levels.
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(hr)) goto cleanup0;
// Create an instance of the Task Service.
ITaskService *pService = NULL;
hr = CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService);
if (FAILED(hr)) goto cleanup0;
// Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
if (FAILED(hr)) goto cleanup1;
// Get the pointer to the root task folder. This folder will hold the new task that is registered.
ITaskFolder *pRootFolder = NULL;
hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder);
if (FAILED(hr)) goto cleanup1;
// If the same task exists, remove it.
pRootFolder->DeleteTask(_bstr_t(TASKNAME), 0);
// Create the task builder object to create the task.
ITaskDefinition *pTask = NULL;
hr = pService->NewTask(0, &pTask);
// COM clean up. Pointer is no longer used.
pService->Release();
if (FAILED(hr)) { pRootFolder->Release(); CoUninitialize(); return 1; }
// Get the registration info for setting the identification.
IRegistrationInfo *pRegInfo = NULL;
hr = pTask->get_RegistrationInfo(&pRegInfo);
if (FAILED(hr)) goto cleanup2;
hr = pRegInfo->put_Author(L"Author Name");
pRegInfo->Release();
if (FAILED(hr)) goto cleanup2;
// Create the settings for the task
ITaskSettings *pSettings = NULL;
hr = pTask->get_Settings(&pSettings);
if (FAILED(hr)) goto cleanup2;
// Set setting values for the task.
pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE);
pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S"));
pSettings->Release();
if (FAILED(hr)) goto cleanup2;
// Get the trigger collection to insert the logon trigger.
ITriggerCollection *pTriggerCollection = NULL;
hr = pTask->get_Triggers(&pTriggerCollection);
if (FAILED(hr)) goto cleanup2;
// Add the logon trigger to the task.
ITrigger *pTrigger = NULL;
hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger);
pTriggerCollection->Release();
if (FAILED(hr)) goto cleanup2;
ILogonTrigger *pLogonTrigger = NULL;
hr = pTrigger->QueryInterface(IID_ILogonTrigger, (void**)&pLogonTrigger);
pTrigger->Release();
if (FAILED(hr)) goto cleanup2;
hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1"));
if (FAILED(hr)) goto cleanup2;
// Define the user. The task will execute when the user logs on. The specified user must be a user on this computer.
//hr = pLogonTrigger->put_UserId(_bstr_t(L"DOMAIN\\UserName"));
pLogonTrigger->Release();
if (FAILED(hr)) goto cleanup2;
IPrincipal *pPrincipal;
hr = pTask->get_Principal(&pPrincipal);
if (FAILED(hr)) goto cleanup2;
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
if (FAILED(hr)) goto cleanup2;
// Add an Action to the task. This task will execute .exe
IActionCollection *pActionCollection = NULL;
// Get the task action collection pointer.
hr = pTask->get_Actions(&pActionCollection);
if (FAILED(hr)) goto cleanup2;
// Create the action, specifying that it is an executable action.
IAction *pAction = NULL;
hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
if (FAILED(hr)) goto cleanup2;
// QI for the executable task pointer.
IExecAction *pExecAction = NULL;
hr = pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction);
pAction->Release();
if (FAILED(hr)) goto cleanup2;
// Set the path of the executable.
hr = pExecAction->put_Path(_bstr_t(wstrExecutablePath.c_str()));
pExecAction->Release();
if (FAILED(hr)) goto cleanup2;
// Save the task in the root folder.
IRegisteredTask *pRegisteredTask = NULL;
hr = pRootFolder->RegisterTaskDefinition(_bstr_t(TASKNAME), pTask, TASK_CREATE_OR_UPDATE, _variant_t(L"S-1-5-32-544"), _variant_t(), TASK_LOGON_GROUP, _variant_t(L""), &pRegisteredTask); //_variant_t(L"Builtin\\Administrators"),
if (FAILED(hr)) goto cleanup2;
printf("Success! Task successfully registered.");
getchar();
pRootFolder->Release();
pTask->Release();
pRegisteredTask->Release();
CoUninitialize();
return 0;
cleanup0:
CoUninitialize();
return 1;
cleanup1:
pService->Release();
CoUninitialize();
return 1;
cleanup2:
pRootFolder->Release();
pTask->Release();
CoUninitialize();
return 1;
}
I suspect the demo code you have is XP-era, and hasn't been updated to match the Vista/Win7 rules.
I updated the sample to set the LUA settings after setting the logon trigger, and it seems to work:
hr = pLogonTrigger->put_UserId(_bstr_t(L"DOMAIN\username"));
if (FAILED(hr))
{
printf("\nCannot add user ID to logon trigger: %x", hr);
CoUninitialize();
return 1;
}
//*** NEW**** Set the LUA settings
CComPtr<IPrincipal> pPrincipal;
hr = pTask->get_Principal(&pPrincipal);
if (SUCCEEDED(hr))
{
hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA);
}
if (SUCCEEDED(hr))
{
hr = pPrincipal->put_GroupId(_bstr_t(L"Builtin\\Administrators"));
}
if (FAILED(hr))
{
printf("\nCannot set runlevel/groupid: %x", hr);
CoUninitialize();
return 1;
}
If you need it to run on XP, then it's likely that the get_Principal call will fail, so let that failure through.
I am using direct show to play media files within my program, and i have been able to play a media file a single time using the following code.
void main()
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
}
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
hr = pGraph->RenderFile(L"C:\\Example.mp3", NULL);
if (SUCCEEDED(hr))
{
hr = pControl->Run();
if (SUCCEEDED(hr))
{
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
}
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
return;
}
My question then becomes how would i make the file continue to play and repeat itself a given number of times, or infinitely if i so desired. IMediaControl has no member named loop.
There is no built in way to do this. Once way of implementing this is that instead of exiting you function when you get the completion event, you seek to the beginning of the file an start playback again.
The following link on event handling may help: Learning When an Event Occurs. EC_COMPLETE event/notification is issued when streaming is complete.
I created an scheduler in C++.I have set all the parameters and the task is configured to run only when the user is logged on with the user name provided(Done by setting the TASK_FLAG_RUN_ONLY_IF_LOGGED_ON flag).
When I try to run the task I get a status "Could not start". Now suppose I manually edit any property in task property and click on OK the task runs fine.
Note:The manual edit specified may be anything, like just adding a space at the end of the excecutable name or the user name. What may be the problem?
Below is the code i am using:
#include <windows.h>
#include <initguid.h>
#include <ole2.h>
#include <mstask.h>
#include <msterr.h>
#include <wchar.h>
#include<stdio.h>
#include<conio.h>
#pragma comment(lib, "Mstask.lib")
#pragma comment(lib, "ole32.lib")
int main(int argc, char **argv)
{
HRESULT hr = S_OK;
ITaskScheduler *pITS;
///////////////////////////////////////////////////////////////////
// Call CoInitialize to initialize the COM library and then
// CoCreateInstance to get the Task Scheduler object.
///////////////////////////////////////////////////////////////////
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return 1;
}
}
else
{
return 1;
}
LPCWSTR pwszTaskName;
ITask *pITask;
pwszTaskName = L"TestTask";
hr = pITS->NewWorkItem(pwszTaskName,
CLSID_CTask,
IID_ITask,
(IUnknown**)&pITask);
if (FAILED(hr))
{
wprintf(L"Failed calling ITaskScheduler::NewWorkItem: ");
wprintf(L"error = 0x%x\n",hr);
CoUninitialize();
return 1;
}
LPCWSTR pwszApplicationName = L"C:\\windows\\notepad.exe";
hr = pITask->SetApplicationName(pwszApplicationName);
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::SetApplicationName: ");
wprintf(L"error = 0x%x\n",hr);
pITS->Release();
pITask->Release();
CoUninitialize();
return 1;
}
pITask->SetAccountInformation(L"USERNAME", NULL);
pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
pITask->SetWorkingDirectory(L"C:\\windows");
ITaskTrigger *pITaskTrigger;
WORD piNewTrigger;
hr = pITask->CreateTrigger(&piNewTrigger,
&pITaskTrigger);
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::CreatTrigger: ");
wprintf(L"error = 0x%x\n",hr);
pITask->Release();
CoUninitialize();
return 1;
}
pITS->AddWorkItem(pwszTaskName, pITask);
pITS->Release(); // Release sceduler
hr = pITask->Run();
if (FAILED(hr))
{
wprintf(L"Failed calling ITask::Run, error = 0x%x\n",hr);
pITask->Release();
CoUninitialize();
return 1;
}
pITask->Release();
CoUninitialize();
_getch();
return 0;
}
I think you need to test all return values, that could be revealing. I'm mostly suspicious about:
pITask->SetAccountInformation(L"USERNAME", NULL);
pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
Readinig http://msdn.microsoft.com/en-us/library/aa381276(VS.85).aspx I got the impression that you need to call SetFlags first and then SetAccountInformation.
I've had the same problem on XP: status "Could not start" and all ok after manual editing.
Solution:
Go to Advanced -> View Log. And see the reason for the fail.
In my case there was "The attempt to retrieve account information for the specified task failed". So I've just needed to get user name via GetUserName and set it via SetAccountInformation. Note order of SetAccountInformation and SetFlags doesn't matter.
Take a look here for other reasons.
May be it will help someone someday.