[PATCH 7/7] schedsvc: Implement NetrJobAdd.

Dmitry Timoshkov dmitry at baikal.ru
Tue Apr 17 02:12:17 CDT 2018


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/schedsvc/atsvc.c          | 230 ++++++++++++++++++++++++++++++++++++++++-
 dlls/schedsvc/tests/atsvcapi.c |   1 -
 2 files changed, 228 insertions(+), 3 deletions(-)

diff --git a/dlls/schedsvc/atsvc.c b/dlls/schedsvc/atsvc.c
index c4a4e9f421..6aa4ae0594 100644
--- a/dlls/schedsvc/atsvc.c
+++ b/dlls/schedsvc/atsvc.c
@@ -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)
 {
     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)
 {
-    FIXME("%s,%p,%p: stub\n", debugstr_w(server_name), info, jobid);
-    return ERROR_NOT_SUPPORTED;
+    WCHAR windir[MAX_PATH];
+
+    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(&current_jobid);
+    }
+
+    return ERROR_SUCCESS;
 }
 
 DWORD __cdecl NetrJobDel(ATSVC_HANDLE server_name, DWORD min_jobid, DWORD max_jobid)
diff --git a/dlls/schedsvc/tests/atsvcapi.c b/dlls/schedsvc/tests/atsvcapi.c
index d429232913..2226480a35 100644
--- a/dlls/schedsvc/tests/atsvcapi.c
+++ b/dlls/schedsvc/tests/atsvcapi.c
@@ -91,7 +91,6 @@ START_TEST(atsvcapi)
         win_skip("NetrJobAdd: Access denied, skipping the tests\n");
         goto skip_tests;
     }
-todo_wine
     ok(ret == ERROR_SUCCESS || broken(ret == ERROR_NOT_SUPPORTED) /* Win8+ */, "NetrJobAdd error %u\n", ret);
     if (ret == ERROR_NOT_SUPPORTED)
     {
-- 
2.16.3




More information about the wine-devel mailing list