atsvcapi.c 7.27 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 * Copyright 2018 Dmitry Timoshkov
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <windows.h>
#include <ole2.h>
#include <rpcdce.h>
#include <mstask.h>
#include "atsvc.h"

#include "wine/test.h"

/* lmat.h defines those, but other types in that file conflict
 * with generated atsvc.h typedefs.
 */
#define JOB_ADD_CURRENT_DATE 0x08
#define JOB_NONINTERACTIVE   0x10

34
extern handle_t atsvc_handle;
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

static int test_failures, test_skipped;

static LONG CALLBACK rpc_exception_filter(EXCEPTION_POINTERS *ptrs)
{
    if (test_skipped)
        skip("Can't connect to ATSvc service: %#x\n", ptrs->ExceptionRecord->ExceptionCode);

    if (winetest_debug)
    {
        fprintf(stdout, "%04x:atsvcapi: 1 tests executed (0 marked as todo, %d %s), %d skipped.\n",
                GetCurrentProcessId(), test_failures, test_failures != 1 ? "failures" : "failure", test_skipped);
        fflush(stdout);
    }
    ExitProcess(test_failures);
}

START_TEST(atsvcapi)
{
    static unsigned char ncalrpc[] = "ncalrpc";
55
    static WCHAR task1W[] = L"Task1.exe";
56 57 58 59 60
    HRESULT hr;
    unsigned char *binding_str;
    WCHAR server_name[MAX_COMPUTERNAME_LENGTH + 1];
    PTOP_LEVEL_EXCEPTION_FILTER old_exception_filter;
    AT_ENUM_CONTAINER container;
61
    AT_INFO info, *info2;
62 63 64 65 66 67 68 69 70 71
    DWORD ret, i, total, start_index, jobid, try, try_count;
    BOOL found;

    total = MAX_COMPUTERNAME_LENGTH + 1;
    SetLastError(0xdeadbeef);
    ret = GetComputerNameW(server_name, &total);
    ok(ret, "GetComputerName error %u\n", GetLastError());

    hr = RpcStringBindingComposeA(NULL, ncalrpc, NULL, NULL, NULL, &binding_str);
    ok(hr == RPC_S_OK, "RpcStringBindingCompose error %#x\n", hr);
72
    hr = RpcBindingFromStringBindingA(binding_str, &atsvc_handle);
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    ok(hr == RPC_S_OK, "RpcBindingFromStringBinding error %#x\n", hr);
    hr = RpcStringFreeA(&binding_str);
    ok(hr == RPC_S_OK, "RpcStringFree error %#x\n", hr);

    /* widl generated RpcTryExcept/RpcExcept can't catch raised exceptions */
    old_exception_filter = SetUnhandledExceptionFilter(rpc_exception_filter);

    /* If the first call fails that's probably because the service is not running */
    test_failures = 0;
    test_skipped = 1;

    memset(&info, 0, sizeof(info));
    info.Flags = JOB_ADD_CURRENT_DATE | JOB_NONINTERACTIVE;
    info.Command = task1W;
    jobid = 0;
    ret = NetrJobAdd(server_name, &info, &jobid);
    if (ret == ERROR_ACCESS_DENIED)
    {
        win_skip("NetrJobAdd: Access denied, skipping the tests\n");
        goto skip_tests;
    }
    ok(ret == ERROR_SUCCESS || broken(ret == ERROR_NOT_SUPPORTED) /* Win8+ */, "NetrJobAdd error %u\n", ret);
    if (ret == ERROR_NOT_SUPPORTED)
    {
        /* FIXME: use win_skip() when todo_wine above is removed */
        skip("NetrJobAdd is not supported on this platform\n");
        goto skip_tests;
    }
    ok(jobid != 0, "jobid should not be 0\n");

    /* From now on: if the call fails that's a failure */
    test_failures = 1;
    test_skipped = 0;

107 108 109 110
    info2 = NULL;
    ret = NetrJobGetInfo(server_name, 0xdeadbeef, &info2);
    ok(ret == APE_AT_ID_NOT_FOUND || broken(1) /* vista and w2008 return rubbish here */, "wrong error %u\n", ret);

111 112 113
    ret = NetrJobDel(server_name, 0xdeadbeef, 0xdeadbeef);
    ok(ret == APE_AT_ID_NOT_FOUND, "wrong error %u\n", ret);

114 115 116 117 118 119 120
    try_count = 5;

    for (try = 1; try <= try_count; try++)
    {
        container.EntriesRead = 0;
        container.Buffer = NULL;
        total = start_index = 0;
121
        ret = NetrJobEnum(server_name, &container, -1, &total, &start_index);
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
        if (ret == ERROR_ACCESS_DENIED)
        {
            win_skip("NetrJobEnum: Access denied, skipping the tests\n");
            goto skip_tests_delete;
        }
        ok(ret == ERROR_SUCCESS, "NetrJobEnum error %u (%#x)\n", ret, ret);
        ok(total != 0, "total %u\n", total);
        ok(start_index == 0, "start_index %u\n", start_index);
        ok(container.Buffer != NULL, "Buffer %p\n", container.Buffer);
        ok(container.EntriesRead != 0, "EntriesRead %u\n", container.EntriesRead);

        found = FALSE;

        for (i = 0; i < container.EntriesRead; i++)
        {
            trace("%u: jobid %u, command %s\n", i, container.Buffer[i].JobId, wine_dbgstr_w(container.Buffer[i].Command));

            if (container.Buffer[i].JobId == jobid ||
                !lstrcmpW(container.Buffer[i].Command, task1W))
            {
                found = TRUE;
                trace("found %u: jobid %u, command %s\n", i, container.Buffer[i].JobId, wine_dbgstr_w(container.Buffer[i].Command));
            }

            info2 = NULL;
            ret = NetrJobGetInfo(server_name, container.Buffer[i].JobId, &info2);
            ok(ret == ERROR_SUCCESS, "NetrJobGetInfo error %u\n", ret);

            ok(container.Buffer[i].JobTime == info2->JobTime, "%u != %u\n", (UINT)container.Buffer[i].JobTime, (UINT)info2->JobTime);
            ok(container.Buffer[i].DaysOfMonth == info2->DaysOfMonth, "%u != %u\n", container.Buffer[i].DaysOfMonth, info2->DaysOfMonth);
            ok(container.Buffer[i].DaysOfWeek == info2->DaysOfWeek, "%u != %u\n", container.Buffer[i].DaysOfWeek, info2->DaysOfWeek);
            ok(container.Buffer[i].Flags == info2->Flags, "%#x != %#x\n", container.Buffer[i].Flags, info2->Flags);
            ok(!lstrcmpW(container.Buffer[i].Command, info2->Command), "%s != %s\n", wine_dbgstr_w(container.Buffer[i].Command), wine_dbgstr_w(info2->Command));

            MIDL_user_free(container.Buffer[i].Command);
            MIDL_user_free(info2->Command);
            MIDL_user_free(info2);
        }

        if (found)
            break;
    }

    MIDL_user_free(container.Buffer);

    ok(found, "just added jobid %u should be found\n", jobid);

skip_tests_delete:
    ret = NetrJobDel(server_name, jobid, jobid);
    ok(ret == ERROR_SUCCESS, "NetrJobDel error %u\n", ret);

skip_tests:
    SetUnhandledExceptionFilter(old_exception_filter);

176
    hr = RpcBindingFree(&atsvc_handle);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    ok(hr == RPC_S_OK, "RpcBindingFree error %#x\n", hr);
}

DECLSPEC_HIDDEN handle_t __RPC_USER ATSVC_HANDLE_bind(ATSVC_HANDLE str)
{
    static unsigned char ncalrpc[] = "ncalrpc";
    unsigned char *binding_str;
    handle_t rpc_handle;
    HRESULT hr;

    hr = RpcStringBindingComposeA(NULL, ncalrpc, NULL, NULL, NULL, &binding_str);
    ok(hr == RPC_S_OK, "RpcStringBindingCompose error %#x\n", hr);

    hr = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
    ok(hr == RPC_S_OK, "RpcBindingFromStringBinding error %#x\n", hr);

    RpcStringFreeA(&binding_str);
    return rpc_handle;
}

DECLSPEC_HIDDEN void __RPC_USER ATSVC_HANDLE_unbind(ATSVC_HANDLE ServerName, handle_t rpc_handle)
{
    RpcBindingFree(&rpc_handle);
}