schedsvc: Implement NetrJobAdd.
Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
934a64919d
commit
ba55cce8bc
|
@ -327,6 +327,180 @@ void add_job(const WCHAR *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL write_signature(HANDLE hfile)
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SignatureVersion;
|
||||||
|
USHORT ClientVersion;
|
||||||
|
BYTE md5[64];
|
||||||
|
} signature;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
signature.SignatureVersion = 0x0001;
|
||||||
|
signature.ClientVersion = 0x0001;
|
||||||
|
memset(&signature.md5, 0, sizeof(signature.md5));
|
||||||
|
|
||||||
|
return WriteFile(hfile, &signature, sizeof(signature), &size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL write_reserved_data(HANDLE hfile)
|
||||||
|
{
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
USHORT size;
|
||||||
|
BYTE data[8];
|
||||||
|
} user = { 8, { 0xff,0x0f,0x1d,0,0,0,0,0 } };
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
return WriteFile(hfile, &user, sizeof(user), &size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL write_trigger(HANDLE hfile, const AT_INFO *info)
|
||||||
|
{
|
||||||
|
USHORT count;
|
||||||
|
DWORD size;
|
||||||
|
SYSTEMTIME st;
|
||||||
|
TASK_TRIGGER trigger;
|
||||||
|
|
||||||
|
count = 1;
|
||||||
|
if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
GetSystemTime(&st);
|
||||||
|
if (!(info->Flags & JOB_ADD_CURRENT_DATE))
|
||||||
|
{
|
||||||
|
/* FIXME: parse AT_INFO */
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.cbTriggerSize = sizeof(trigger);
|
||||||
|
trigger.Reserved1 = 0;
|
||||||
|
trigger.wBeginYear = st.wYear;
|
||||||
|
trigger.wBeginMonth = st.wMonth;
|
||||||
|
trigger.wBeginDay = st.wDay;
|
||||||
|
trigger.wEndYear = st.wYear;
|
||||||
|
trigger.wEndMonth = st.wMonth;
|
||||||
|
trigger.wEndDay = st.wDay;
|
||||||
|
trigger.wStartHour = st.wHour;
|
||||||
|
trigger.wStartMinute = st.wMinute;
|
||||||
|
trigger.MinutesDuration = 0;
|
||||||
|
trigger.MinutesInterval = 0;
|
||||||
|
/* FIXME */
|
||||||
|
trigger.rgFlags = TASK_TRIGGER_FLAG_HAS_END_DATE;
|
||||||
|
trigger.TriggerType = TASK_TIME_TRIGGER_MONTHLYDATE;
|
||||||
|
trigger.Type.MonthlyDate.rgfDays = 0;
|
||||||
|
trigger.Type.MonthlyDate.rgfMonths = 0xffff;
|
||||||
|
trigger.Reserved2 = 0;
|
||||||
|
trigger.wRandomMinutesInterval = 0;
|
||||||
|
|
||||||
|
return WriteFile(hfile, &trigger, sizeof(trigger), &size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL write_unicode_string(HANDLE hfile, const WCHAR *str)
|
||||||
|
{
|
||||||
|
USHORT count;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
count = str ? (lstrlenW(str) + 1) : 0;
|
||||||
|
if (!WriteFile(hfile, &count, sizeof(count), &size, NULL))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!str) return TRUE;
|
||||||
|
|
||||||
|
count *= sizeof(WCHAR);
|
||||||
|
return WriteFile(hfile, str, count, &size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL create_job(const WCHAR *job_name, const AT_INFO *info)
|
||||||
|
{
|
||||||
|
static WCHAR authorW[] = { 'W','i','n','e',0 };
|
||||||
|
static WCHAR commentW[] = { 'C','r','e','a','t','e','d',' ','b','y',' ','W','i','n','e',0 };
|
||||||
|
FIXDLEN_DATA fixed;
|
||||||
|
USHORT word;
|
||||||
|
HANDLE hfile;
|
||||||
|
DWORD size, ver;
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
|
||||||
|
TRACE("trying to create job %s\n", debugstr_w(job_name));
|
||||||
|
hfile = CreateFileW(job_name, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0);
|
||||||
|
if (hfile == INVALID_HANDLE_VALUE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ver = GetVersion();
|
||||||
|
fixed.product_version = MAKEWORD(ver >> 8, ver);
|
||||||
|
fixed.file_version = 0x0001;
|
||||||
|
UuidCreate(&fixed.uuid);
|
||||||
|
fixed.name_size_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
|
||||||
|
fixed.trigger_offset = sizeof(fixed) + sizeof(USHORT); /* FIXDLEN_DATA + Instance Count */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT) + (lstrlenW(info->Command) + 1) * sizeof(WCHAR); /* Application Name */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT); /* Parameters */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT); /* Working Directory */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT) + (lstrlenW(authorW) + 1) * sizeof(WCHAR); /* Author */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT) + (lstrlenW(commentW) + 1) * sizeof(WCHAR); /* Comment */
|
||||||
|
fixed.trigger_offset += sizeof(USHORT); /* User Data */
|
||||||
|
fixed.trigger_offset += 10; /* Reserved Data */
|
||||||
|
fixed.error_retry_count = 0;
|
||||||
|
fixed.error_retry_interval = 0;
|
||||||
|
fixed.idle_deadline = 60;
|
||||||
|
fixed.idle_wait = 10;
|
||||||
|
fixed.priority = NORMAL_PRIORITY_CLASS;
|
||||||
|
fixed.maximum_runtime = 259200000;
|
||||||
|
fixed.exit_code = 0;
|
||||||
|
fixed.status = SCHED_S_TASK_HAS_NOT_RUN;
|
||||||
|
fixed.flags = TASK_FLAG_DELETE_WHEN_DONE;
|
||||||
|
if (!(info->Flags & JOB_NONINTERACTIVE))
|
||||||
|
fixed.flags |= TASK_FLAG_INTERACTIVE;
|
||||||
|
/* FIXME: add other flags */
|
||||||
|
memset(&fixed.last_runtime, 0, sizeof(fixed.last_runtime));
|
||||||
|
|
||||||
|
if (!WriteFile(hfile, &fixed, sizeof(fixed), &size, NULL))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* Instance Count */
|
||||||
|
word = 0;
|
||||||
|
if (!WriteFile(hfile, &word, sizeof(word), &size, NULL))
|
||||||
|
goto failed;
|
||||||
|
/* Application Name */
|
||||||
|
if (!write_unicode_string(hfile, info->Command))
|
||||||
|
goto failed;
|
||||||
|
/* Parameters */
|
||||||
|
if (!write_unicode_string(hfile, NULL))
|
||||||
|
goto failed;
|
||||||
|
/* Working Directory */
|
||||||
|
if (!write_unicode_string(hfile, NULL))
|
||||||
|
goto failed;
|
||||||
|
/* Author */
|
||||||
|
if (!write_unicode_string(hfile, authorW))
|
||||||
|
goto failed;
|
||||||
|
/* Comment */
|
||||||
|
if (!write_unicode_string(hfile, commentW))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* User Data */
|
||||||
|
word = 0;
|
||||||
|
if (!WriteFile(hfile, &word, sizeof(word), &size, NULL))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* Reserved Data */
|
||||||
|
if (!write_reserved_data(hfile))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* Trigegrs */
|
||||||
|
if (!write_trigger(hfile, info))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
/* Signature */
|
||||||
|
if (!write_signature(hfile))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
CloseHandle(hfile);
|
||||||
|
if (!ret) DeleteFileW(job_name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct job_t *find_job(DWORD jobid, const WCHAR *name)
|
static struct job_t *find_job(DWORD jobid, const WCHAR *name)
|
||||||
{
|
{
|
||||||
struct job_t *job;
|
struct job_t *job;
|
||||||
|
@ -357,8 +531,60 @@ void remove_job(const WCHAR *name)
|
||||||
|
|
||||||
DWORD __cdecl NetrJobAdd(ATSVC_HANDLE server_name, AT_INFO *info, DWORD *jobid)
|
DWORD __cdecl NetrJobAdd(ATSVC_HANDLE server_name, AT_INFO *info, DWORD *jobid)
|
||||||
{
|
{
|
||||||
FIXME("%s,%p,%p: stub\n", debugstr_w(server_name), info, jobid);
|
WCHAR windir[MAX_PATH];
|
||||||
return ERROR_NOT_SUPPORTED;
|
|
||||||
|
TRACE("%s,%p,%p\n", debugstr_w(server_name), info, jobid);
|
||||||
|
|
||||||
|
GetWindowsDirectoryW(windir, MAX_PATH);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
static const WCHAR fmtW[] = { '\\','T','a','s','k','s','\\','A','t','%','u','.','j','o','b',0 };
|
||||||
|
WCHAR task_name[MAX_PATH], name[32];
|
||||||
|
|
||||||
|
strcpyW(task_name, windir);
|
||||||
|
sprintfW(name, fmtW, current_jobid);
|
||||||
|
strcatW(task_name, name);
|
||||||
|
if (create_job(task_name, info))
|
||||||
|
{
|
||||||
|
struct job_t *job;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&at_job_list_section);
|
||||||
|
job = find_job(0, task_name);
|
||||||
|
LeaveCriticalSection(&at_job_list_section);
|
||||||
|
|
||||||
|
if (job)
|
||||||
|
{
|
||||||
|
*jobid = job->info.JobId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!job)
|
||||||
|
{
|
||||||
|
ERR("couldn't find just created job %s\n", debugstr_w(task_name));
|
||||||
|
return ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() != ERROR_FILE_EXISTS)
|
||||||
|
{
|
||||||
|
|
||||||
|
TRACE("create_job error %u\n", GetLastError());
|
||||||
|
return GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
InterlockedIncrement(¤t_jobid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD __cdecl NetrJobDel(ATSVC_HANDLE server_name, DWORD min_jobid, DWORD max_jobid)
|
DWORD __cdecl NetrJobDel(ATSVC_HANDLE server_name, DWORD min_jobid, DWORD max_jobid)
|
||||||
|
|
|
@ -91,7 +91,6 @@ START_TEST(atsvcapi)
|
||||||
win_skip("NetrJobAdd: Access denied, skipping the tests\n");
|
win_skip("NetrJobAdd: Access denied, skipping the tests\n");
|
||||||
goto skip_tests;
|
goto skip_tests;
|
||||||
}
|
}
|
||||||
todo_wine
|
|
||||||
ok(ret == ERROR_SUCCESS || broken(ret == ERROR_NOT_SUPPORTED) /* Win8+ */, "NetrJobAdd error %u\n", ret);
|
ok(ret == ERROR_SUCCESS || broken(ret == ERROR_NOT_SUPPORTED) /* Win8+ */, "NetrJobAdd error %u\n", ret);
|
||||||
if (ret == ERROR_NOT_SUPPORTED)
|
if (ret == ERROR_NOT_SUPPORTED)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue