Paul Gofman : schedsvc: Read task enable state from XML in SchRpcGetTaskInfo().

Alexandre Julliard julliard at winehq.org
Mon Jul 18 15:45:51 CDT 2022


Module: wine
Branch: master
Commit: 6e7f5f8e5fceef78b11950598b58fd3b0816df7b
URL:    https://gitlab.winehq.org/wine/wine/-/commit/6e7f5f8e5fceef78b11950598b58fd3b0816df7b

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Fri Jul 15 17:31:26 2022 -0500

schedsvc: Read task enable state from XML in SchRpcGetTaskInfo().

---

 dlls/schedsvc/Makefile.in       |   2 +-
 dlls/schedsvc/schedsvc.c        | 226 +++++++++++++++++++++++++++++++++++++++-
 dlls/taskschd/tests/scheduler.c |   4 -
 3 files changed, 225 insertions(+), 7 deletions(-)

diff --git a/dlls/schedsvc/Makefile.in b/dlls/schedsvc/Makefile.in
index 021cae468a6..ccd483edae2 100644
--- a/dlls/schedsvc/Makefile.in
+++ b/dlls/schedsvc/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = schedsvc.dll
-IMPORTS   = rpcrt4 advapi32 ole32
+IMPORTS   = rpcrt4 advapi32 ole32 xmllite
 
 C_SRCS = \
 	atsvc.c \
diff --git a/dlls/schedsvc/schedsvc.c b/dlls/schedsvc/schedsvc.c
index ee200d94a6c..ba6da110fe5 100644
--- a/dlls/schedsvc/schedsvc.c
+++ b/dlls/schedsvc/schedsvc.c
@@ -20,7 +20,12 @@
 
 #include <stdarg.h>
 
+#define COBJMACROS
+
 #include "windef.h"
+#include "initguid.h"
+#include "objbase.h"
+#include "xmllite.h"
 #include "schrpc.h"
 #include "taskschd.h"
 #include "wine/debug.h"
@@ -31,6 +36,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(schedsvc);
 
 static const char bom_utf8[] = { 0xef,0xbb,0xbf };
 
+struct task_info
+{
+    BOOL enabled;
+};
+
 HRESULT __cdecl SchRpcHighestVersion(DWORD *version)
 {
     TRACE("%p\n", version);
@@ -310,6 +320,212 @@ static HRESULT read_xml(const WCHAR *name, WCHAR **xml)
     return hr;
 }
 
+static HRESULT read_text_value(IXmlReader *reader, WCHAR **value)
+{
+    HRESULT hr;
+    XmlNodeType type;
+
+    while (IXmlReader_Read(reader, &type) == S_OK)
+    {
+        switch (type)
+        {
+            case XmlNodeType_Text:
+                if (FAILED(hr = IXmlReader_GetValue(reader, (const WCHAR **)value, NULL)))
+                    return hr;
+                TRACE("%s\n", debugstr_w(*value));
+                return S_OK;
+
+            case XmlNodeType_Whitespace:
+            case XmlNodeType_Comment:
+                break;
+
+            default:
+                FIXME("unexpected node type %d\n", type);
+                return E_FAIL;
+        }
+    }
+
+    return E_FAIL;
+}
+
+static HRESULT read_variantbool_value(IXmlReader *reader, VARIANT_BOOL *vbool)
+{
+    WCHAR *value;
+    HRESULT hr;
+
+    *vbool = VARIANT_FALSE;
+
+    if (FAILED(hr = read_text_value(reader, &value)))
+        return hr;
+
+    if (!wcscmp(value, L"true"))
+    {
+        *vbool = VARIANT_TRUE;
+    }
+    else if (wcscmp(value, L"false"))
+    {
+        WARN("unexpected bool value %s\n", debugstr_w(value));
+        return SCHED_E_INVALIDVALUE;
+    }
+
+    return S_OK;
+}
+
+static HRESULT read_task_settings(IXmlReader *reader, struct task_info *info)
+{
+    VARIANT_BOOL bool_val;
+    const WCHAR *name;
+    XmlNodeType type;
+    HRESULT hr;
+
+    if (IXmlReader_IsEmptyElement(reader))
+    {
+        TRACE("Settings is empty.\n");
+        return S_OK;
+    }
+
+    while (IXmlReader_Read(reader, &type) == S_OK)
+    {
+        switch (type)
+        {
+            case XmlNodeType_EndElement:
+                hr = IXmlReader_GetLocalName(reader, &name, NULL);
+                if (hr != S_OK) return hr;
+
+                TRACE("/%s\n", debugstr_w(name));
+
+                if (!wcscmp(name, L"Settings"))
+                    return S_OK;
+
+                break;
+
+            case XmlNodeType_Element:
+                hr = IXmlReader_GetLocalName(reader, &name, NULL);
+                if (hr != S_OK) return hr;
+
+                TRACE("Element: %s\n", debugstr_w(name));
+
+                if (!wcscmp(name, L"Enabled"))
+                {
+                    if (FAILED(hr = read_variantbool_value(reader, &bool_val)))
+                        return hr;
+                    info->enabled = !!bool_val;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    WARN("Settings was not terminated\n");
+    return SCHED_E_MALFORMEDXML;
+}
+
+static HRESULT read_task_info(IXmlReader *reader, struct task_info *info)
+{
+    const WCHAR *name;
+    XmlNodeType type;
+    HRESULT hr;
+
+    if (IXmlReader_IsEmptyElement(reader))
+    {
+        TRACE("Task is empty\n");
+        return S_OK;
+    }
+    while (IXmlReader_Read(reader, &type) == S_OK)
+    {
+        switch (type)
+        {
+            case XmlNodeType_EndElement:
+                if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
+                    return hr;
+
+                if (!wcscmp(name, L"Task"))
+                    return S_OK;
+                break;
+
+            case XmlNodeType_Element:
+                if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
+                    return hr;
+
+                TRACE("Element: %s\n", debugstr_w(name));
+
+                if (!wcscmp(name, L"Settings"))
+                {
+                    if (FAILED(hr = read_task_settings(reader, info)))
+                        return hr;
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    WARN("Task was not terminated\n");
+    return SCHED_E_MALFORMEDXML;
+
+}
+
+static HRESULT read_task_info_from_xml(const WCHAR *xml, struct task_info *info)
+{
+    IXmlReader *reader;
+    const WCHAR *name;
+    XmlNodeType type;
+    IStream *stream;
+    HGLOBAL hmem;
+    HRESULT hr;
+    void *buf;
+
+    memset(info, 0, sizeof(*info));
+
+    if (!(hmem = GlobalAlloc(0, wcslen(xml) * sizeof(WCHAR))))
+        return E_OUTOFMEMORY;
+
+    buf = GlobalLock(hmem);
+    memcpy(buf, xml, lstrlenW(xml) * sizeof(WCHAR));
+    GlobalUnlock(hmem);
+
+    if (FAILED(hr = CreateStreamOnHGlobal(hmem, TRUE, &stream)))
+    {
+        GlobalFree(hmem);
+        return hr;
+    }
+
+    if (FAILED(hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL)))
+    {
+        IStream_Release(stream);
+        return hr;
+    }
+
+    if (FAILED(hr = IXmlReader_SetInput(reader, (IUnknown *)stream)))
+        goto done;
+
+    while (IXmlReader_Read(reader, &type) == S_OK)
+    {
+        if (type != XmlNodeType_Element) continue;
+        if (FAILED(hr = IXmlReader_GetLocalName(reader, &name, NULL)))
+            goto done;
+
+        TRACE("Element: %s\n", debugstr_w(name));
+        if (wcscmp(name, L"Task"))
+            continue;
+
+        hr = read_task_info(reader, info);
+        break;
+    }
+
+done:
+    IXmlReader_Release(reader);
+    IStream_Release(stream);
+    if (FAILED(hr))
+    {
+        WARN("Failed parsing xml, hr %#lx.\n", hr);
+        return SCHED_E_MALFORMEDXML;
+    }
+    return S_OK;
+}
+
 HRESULT __cdecl SchRpcRetrieveTask(const WCHAR *path, const WCHAR *languages, ULONG *n_languages, WCHAR **xml)
 {
     WCHAR *full_name;
@@ -685,6 +901,7 @@ HRESULT __cdecl SchRpcGetLastRunInfo(const WCHAR *path, SYSTEMTIME *last_runtime
 HRESULT __cdecl SchRpcGetTaskInfo(const WCHAR *path, DWORD flags, DWORD *enabled, DWORD *task_state)
 {
     WCHAR *full_name, *xml;
+    struct task_info info;
     HRESULT hr;
 
     FIXME("%s,%#lx,%p,%p: stub\n", debugstr_w(path), flags, enabled, task_state);
@@ -695,10 +912,15 @@ HRESULT __cdecl SchRpcGetTaskInfo(const WCHAR *path, DWORD flags, DWORD *enabled
     hr = read_xml(full_name, &xml);
     heap_free(full_name);
     if (hr != S_OK) return hr;
+    hr = read_task_info_from_xml(xml, &info);
     heap_free(xml);
+    if (FAILED(hr)) return hr;
 
-    *enabled = 0;
-    *task_state = (flags & SCH_FLAG_STATE) ? TASK_STATE_DISABLED : TASK_STATE_UNKNOWN;
+    *enabled = info.enabled;
+    if (flags & SCH_FLAG_STATE)
+        *task_state = *enabled ? TASK_STATE_READY : TASK_STATE_DISABLED;
+    else
+        *task_state = TASK_STATE_UNKNOWN;
     return S_OK;
 }
 
diff --git a/dlls/taskschd/tests/scheduler.c b/dlls/taskschd/tests/scheduler.c
index 4a97d831795..e2f985650e0 100644
--- a/dlls/taskschd/tests/scheduler.c
+++ b/dlls/taskschd/tests/scheduler.c
@@ -860,11 +860,9 @@ static void test_GetTask(void)
     SysFreeString(bstr);
     hr = IRegisteredTask_get_State(task2, &state);
     ok(hr == S_OK, "get_State error %#lx\n", hr);
-    todo_wine
     ok(state == TASK_STATE_READY, "expected TASK_STATE_READY, got %d\n", state);
     hr = IRegisteredTask_get_Enabled(task2, &vbool);
     ok(hr == S_OK, "get_Enabled error %#lx\n", hr);
-    todo_wine
     ok(vbool == VARIANT_TRUE, "expected VARIANT_TRUE, got %d\n", vbool);
 
     IRegisteredTask_Release(task2);
@@ -919,11 +917,9 @@ static void test_GetTask(void)
     SysFreeString(bstr);
     hr = IRegisteredTask_get_State(task2, &state);
     ok(hr == S_OK, "get_State error %#lx\n", hr);
-    todo_wine
     ok(state == TASK_STATE_READY, "expected TASK_STATE_READY, got %d\n", state);
     hr = IRegisteredTask_get_Enabled(task2, &vbool);
     ok(hr == S_OK, "get_Enabled error %#lx\n", hr);
-    todo_wine
     ok(vbool == VARIANT_TRUE, "expected VARIANT_TRUE, got %d\n", vbool);
 
     hr = IRegisteredTask_get_State(task2, NULL);




More information about the wine-cvs mailing list