Jacek Caban : schtests: Added /create command implementation.
Alexandre Julliard
julliard at winehq.org
Fri Jan 19 15:43:21 CST 2018
Module: wine
Branch: master
Commit: 74b386d4a25d6823e2c7f5f03d52f299fac1fe7b
URL: https://source.winehq.org/git/wine.git/?a=commit;h=74b386d4a25d6823e2c7f5f03d52f299fac1fe7b
Author: Jacek Caban <jacek at codeweavers.com>
Date: Fri Jan 19 19:16:29 2018 +0100
schtests: Added /create command implementation.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
programs/schtasks/schtasks.c | 127 +++++++++++++++++++++++++++++++++++++
programs/schtasks/tests/schtasks.c | 72 ++++++++++++++++-----
2 files changed, 182 insertions(+), 17 deletions(-)
diff --git a/programs/schtasks/schtasks.c b/programs/schtasks/schtasks.c
index 88a004f..5967e4a 100644
--- a/programs/schtasks/schtasks.c
+++ b/programs/schtasks/schtasks.c
@@ -27,10 +27,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(schtasks);
static const WCHAR change_optW[] = {'/','c','h','a','n','g','e',0};
+static const WCHAR create_optW[] = {'/','c','r','e','a','t','e',0};
static const WCHAR delete_optW[] = {'/','d','e','l','e','t','e',0};
static const WCHAR enable_optW[] = {'/','e','n','a','b','l','e',0};
static const WCHAR f_optW[] = {'/','f',0};
static const WCHAR tn_optW[] = {'/','t','n',0};
+static const WCHAR xml_optW[] = {'/','x','m','l',0};
static ITaskFolder *get_tasks_root_folder(void)
{
@@ -84,6 +86,51 @@ static IRegisteredTask *get_registered_task(const WCHAR *name)
return registered_task;
}
+static BSTR read_file_to_bstr(const WCHAR *file_name)
+{
+ LARGE_INTEGER file_size;
+ DWORD read_size, size;
+ unsigned char *data;
+ HANDLE file;
+ BOOL r = FALSE;
+ BSTR ret;
+
+ file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ FIXME("Could not open file\n");
+ return NULL;
+ }
+
+ if (!GetFileSizeEx(file, &file_size) || !file_size.QuadPart) {
+ FIXME("Empty file\n");
+ CloseHandle(file);
+ return NULL;
+ }
+
+ data = HeapAlloc(GetProcessHeap(), 0, file_size.QuadPart);
+ if (data)
+ r = ReadFile(file, data, file_size.QuadPart, &read_size, NULL);
+ CloseHandle(file);
+ if (!r) {
+ FIXME("Read filed\n");
+ HeapFree(GetProcessHeap(), 0, data);
+ return NULL;
+ }
+
+ if (read_size > 2 && data[0] == 0xff && data[1] == 0xfe) { /* UTF-16 BOM */
+ ret = SysAllocStringLen((const WCHAR *)(data + 2), (read_size - 2) / sizeof(WCHAR));
+ }else {
+ size = MultiByteToWideChar(CP_ACP, 0, (const char *)data, read_size, NULL, 0);
+ ret = SysAllocStringLen(NULL, size);
+ if (ret)
+ MultiByteToWideChar(CP_ACP, 0, (const char *)data, read_size, ret, size);
+ }
+ HeapFree(GetProcessHeap(), 0, data);
+
+ return ret;
+}
+
static int change_command(int argc, WCHAR *argv[])
{
const WCHAR *task_name;
@@ -132,6 +179,84 @@ static int change_command(int argc, WCHAR *argv[])
return 0;
}
+static int create_command(int argc, WCHAR *argv[])
+{
+ const WCHAR *task_name = NULL, *xml_file = NULL;
+ ITaskFolder *root = NULL;
+ IRegisteredTask *task;
+ VARIANT empty;
+ BSTR str, xml;
+ HRESULT hres;
+
+ while (argc) {
+ if (!strcmpiW(argv[0], xml_optW)) {
+ if (argc < 2) {
+ FIXME("Missing /xml value\n");
+ return 1;
+ }
+
+ if (xml_file) {
+ FIXME("Duplicated /xml argument\n");
+ return 1;
+ }
+
+ xml_file = argv[1];
+ argc -= 2;
+ argv += 2;
+ }else if(!strcmpiW(argv[0], tn_optW)) {
+ if (argc < 2) {
+ FIXME("Missing /tn value\n");
+ return 1;
+ }
+
+ if (task_name) {
+ FIXME("Duplicated /tn argument\n");
+ return 1;
+ }
+
+ task_name = argv[1];
+ argc -= 2;
+ argv += 2;
+ }else {
+ FIXME("Unsupported argument %s\n", debugstr_w(argv[0]));
+ return 1;
+ }
+ }
+
+ if (!task_name) {
+ FIXME("Missing /tn argument\n");
+ return 1;
+ }
+
+ if (!xml_file) {
+ FIXME("Missing /xml argument\n");
+ return E_FAIL;
+ }
+
+ xml = read_file_to_bstr(xml_file);
+ if (!xml)
+ return 1;
+
+ root = get_tasks_root_folder();
+ if (!root) {
+ SysFreeString(xml);
+ return 1;
+ }
+
+ V_VT(&empty) = VT_EMPTY;
+ str = SysAllocString(task_name);
+ hres = ITaskFolder_RegisterTask(root, str, xml, TASK_CREATE, empty, empty,
+ TASK_LOGON_NONE, empty, &task);
+ SysFreeString(str);
+ SysFreeString(xml);
+ ITaskFolder_Release(root);
+ if (FAILED(hres))
+ return 1;
+
+ IRegisteredTask_Release(task);
+ return 0;
+}
+
static int delete_command(int argc, WCHAR *argv[])
{
const WCHAR *task_name = NULL;
@@ -197,6 +322,8 @@ int wmain(int argc, WCHAR *argv[])
FIXME("Print current tasks state\n");
else if (!strcmpiW(argv[1], change_optW))
ret = change_command(argc - 2, argv + 2);
+ else if (!strcmpiW(argv[1], create_optW))
+ ret = create_command(argc - 2, argv + 2);
else if (!strcmpiW(argv[1], delete_optW))
ret = delete_command(argc - 2, argv + 2);
else
diff --git a/programs/schtasks/tests/schtasks.c b/programs/schtasks/tests/schtasks.c
index 7765038..9f1b920 100644
--- a/programs/schtasks/tests/schtasks.c
+++ b/programs/schtasks/tests/schtasks.c
@@ -26,6 +26,23 @@
static ITaskService *service;
static ITaskFolder *root;
+static const char xml_a[] =
+ "<?xml version=\"1.0\"?>\n"
+ "<Task xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n"
+ " <RegistrationInfo>\n"
+ " <Description>\"Task1\"</Description>\n"
+ " </RegistrationInfo>\n"
+ " <Settings>\n"
+ " <Enabled>false</Enabled>\n"
+ " <Hidden>false</Hidden>\n"
+ " </Settings>\n"
+ " <Actions>\n"
+ " <Exec>\n"
+ " <Command>\"task1.exe\"</Command>\n"
+ " </Exec>\n"
+ " </Actions>\n"
+ "</Task>\n";
+
static WCHAR *a2w(const char *str)
{
WCHAR *ret;
@@ -81,23 +98,6 @@ static void _register_task(unsigned line, const char *task_name_a)
WCHAR *task_name, *xml;
HRESULT hres;
- static const char xml_a[] =
- "<?xml version=\"1.0\"?>\n"
- "<Task xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n"
- " <RegistrationInfo>\n"
- " <Description>\"Task1\"</Description>\n"
- " </RegistrationInfo>\n"
- " <Settings>\n"
- " <Enabled>false</Enabled>\n"
- " <Hidden>false</Hidden>\n"
- " </Settings>\n"
- " <Actions>\n"
- " <Exec>\n"
- " <Command>\"task1.exe\"</Command>\n"
- " </Exec>\n"
- " </Actions>\n"
- "</Task>\n";
-
V_VT(&empty) = VT_EMPTY;
task_name = a2w(task_name_a);
xml = a2w(xml_a);
@@ -128,6 +128,23 @@ static void _unregister_task(unsigned line, const char *task_name_a)
HeapFree(GetProcessHeap(), 0, task_name);
}
+static void create_file(const char *file_name, const char *data)
+{
+ HANDLE file;
+ DWORD size;
+ BOOL r;
+
+ file = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
+ if(file == INVALID_HANDLE_VALUE)
+ return;
+
+ r = WriteFile(file, data, strlen(data), &size, NULL);
+ ok(r, "WriteFile failed: %u\n", GetLastError());
+ CloseHandle(file);
+}
+
static BOOL initialize_task_service(void)
{
VARIANT empty;
@@ -186,8 +203,29 @@ START_TEST(schtasks)
r = run_command("schtasks /Change /tn wine\\test\\winetest /enable");
ok(r == 1, "r = %u\n", r);
+ create_file("test.xml", xml_a);
+
+ r = run_command("schtasks /create /xml test.xml /tn wine\\winetest");
+ ok(r == 0, "r = %u\n", r);
+
+ r = run_command("schtasks /change /tn wine\\winetest /enable");
+ ok(r == 0, "r = %u\n", r);
+
+ r = run_command("schtasks /create /xml test.xml /tn wine\\winetest");
+ ok(r == 1, "r = %u\n", r); /* task already exists */
+
+ r = run_command("schtasks /create /tn wine\\winetest");
+ ok(r == E_FAIL, "r = %x\n", r); /* missing arguments */
+
+ r = run_command("schtasks /Delete /f /tn wine\\winetest");
+ ok(r == 0, "r = %u\n", r);
+
+ r = DeleteFileA("test.xml");
+ ok(r, "DeleteFileA failed: %u\n", GetLastError());
+
ITaskFolder_DeleteFolder(root, wine_testW, 0);
ITaskFolder_DeleteFolder(root, wineW, 0);
+
ITaskFolder_Release(root);
ITaskService_Release(service);
CoUninitialize();
More information about the wine-cvs
mailing list