|  | /* | 
|  | * Unit tests for Event Logging functions | 
|  | * | 
|  | * Copyright (c) 2009 Paul Vriens | 
|  | * | 
|  | * 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 <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "winnt.h" | 
|  | #include "winreg.h" | 
|  | #include "sddl.h" | 
|  |  | 
|  | #include "wine/test.h" | 
|  |  | 
|  | static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*); | 
|  | static BOOL (WINAPI *pGetEventLogInformation)(HANDLE,DWORD,LPVOID,DWORD,LPDWORD); | 
|  |  | 
|  | static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD); | 
|  | static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID *); | 
|  | static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID); | 
|  |  | 
|  | static void init_function_pointers(void) | 
|  | { | 
|  | HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); | 
|  | HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); | 
|  |  | 
|  | pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid"); | 
|  | pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation"); | 
|  |  | 
|  | pGetComputerNameExA = (void*)GetProcAddress(hkernel32, "GetComputerNameExA"); | 
|  | pWow64DisableWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64DisableWow64FsRedirection"); | 
|  | pWow64RevertWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64RevertWow64FsRedirection"); | 
|  | } | 
|  |  | 
|  | static void create_backup(const char *filename) | 
|  | { | 
|  | HANDLE handle; | 
|  |  | 
|  | DeleteFileA(filename); | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  | BackupEventLogA(handle, filename); | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | todo_wine | 
|  | ok(GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n"); | 
|  | } | 
|  |  | 
|  | static void test_open_close(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = CloseEventLog(NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE || | 
|  | GetLastError() == ERROR_NOACCESS, /* W2K */ | 
|  | "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenEventLogA(NULL, NULL); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenEventLogA("IDontExist", NULL); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenEventLogA("IDontExist", "deadbeef"); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || | 
|  | GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */ | 
|  | "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError()); | 
|  |  | 
|  | /* This one opens the Application log */ | 
|  | handle = OpenEventLogA(NULL, "deadbeef"); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  | ret = CloseEventLog(handle); | 
|  | ok(ret, "Expected success\n"); | 
|  | /* Close a second time */ | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = CloseEventLog(handle); | 
|  | todo_wine | 
|  | { | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  | } | 
|  |  | 
|  | /* Empty servername should be read as local server */ | 
|  | handle = OpenEventLogA("", "Application"); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  | CloseEventLog(handle); | 
|  | } | 
|  |  | 
|  | static void test_info(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | DWORD needed; | 
|  | EVENTLOG_FULL_INFORMATION efi; | 
|  |  | 
|  | if (!pGetEventLogInformation) | 
|  | { | 
|  | /* NT4 */ | 
|  | win_skip("GetEventLogInformation is not available\n"); | 
|  | return; | 
|  | } | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = pGetEventLogInformation(NULL, 1, NULL, 0, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_LEVEL, "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = pGetEventLogInformation(NULL, EVENTLOG_FULL_INFO, NULL, 0, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, 0, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | needed = 0xdeadbeef; | 
|  | efi.dwFull = 0xdeadbeef; | 
|  | ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, 0, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); | 
|  | ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed); | 
|  | ok(efi.dwFull == 0xdeadbeef, "Expected no change to the dwFull member\n"); | 
|  |  | 
|  | /* Not that we care, but on success last error is set to ERROR_IO_PENDING */ | 
|  | efi.dwFull = 0xdeadbeef; | 
|  | needed *= 2; | 
|  | ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, (LPVOID)&efi, needed, &needed); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed); | 
|  | ok(efi.dwFull == 0 || efi.dwFull == 1, "Expected 0 (not full) or 1 (full), got %d\n", efi.dwFull); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | } | 
|  |  | 
|  | static void test_count(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | DWORD count; | 
|  | const char backup[] = "backup.evt"; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = GetNumberOfEventLogRecords(NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | count = 0xdeadbeef; | 
|  | ret = GetNumberOfEventLogRecords(NULL, &count); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  | ok(count == 0xdeadbeef, "Expected count to stay unchanged\n"); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = GetNumberOfEventLogRecords(handle, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | count = 0xdeadbeef; | 
|  | ret = GetNumberOfEventLogRecords(handle, &count); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(count != 0xdeadbeef, "Expected the number of records\n"); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | /* Make a backup eventlog to work with */ | 
|  | create_backup(backup); | 
|  |  | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | todo_wine | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | /* Does GetNumberOfEventLogRecords work with backup eventlogs? */ | 
|  | count = 0xdeadbeef; | 
|  | ret = GetNumberOfEventLogRecords(handle, &count); | 
|  | todo_wine | 
|  | { | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(count != 0xdeadbeef, "Expected the number of records\n"); | 
|  | } | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  | } | 
|  |  | 
|  | static void test_oldest(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | DWORD oldest; | 
|  | const char backup[] = "backup.evt"; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = GetOldestEventLogRecord(NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | oldest = 0xdeadbeef; | 
|  | ret = GetOldestEventLogRecord(NULL, &oldest); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  | ok(oldest == 0xdeadbeef, "Expected oldest to stay unchanged\n"); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = GetOldestEventLogRecord(handle, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | oldest = 0xdeadbeef; | 
|  | ret = GetOldestEventLogRecord(handle, &oldest); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n"); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | /* Make a backup eventlog to work with */ | 
|  | create_backup(backup); | 
|  |  | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | todo_wine | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | /* Does GetOldestEventLogRecord work with backup eventlogs? */ | 
|  | oldest = 0xdeadbeef; | 
|  | ret = GetOldestEventLogRecord(handle, &oldest); | 
|  | todo_wine | 
|  | { | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n"); | 
|  | } | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  | } | 
|  |  | 
|  | static void test_backup(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | const char backup[] = "backup.evt"; | 
|  | const char backup2[] = "backup2.evt"; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = BackupEventLogA(NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = BackupEventLogA(NULL, backup); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n"); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = BackupEventLogA(handle, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | ret = BackupEventLogA(handle, backup); | 
|  | ok(ret, "Expected success\n"); | 
|  | todo_wine | 
|  | ok(GetFileAttributesA(backup) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n"); | 
|  |  | 
|  | /* Try to overwrite */ | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = BackupEventLogA(handle, backup); | 
|  | todo_wine | 
|  | { | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_ALREADY_EXISTS, "Expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError()); | 
|  | } | 
|  |  | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | /* Can we make a backup of a backup? */ | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | todo_wine | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | ret = BackupEventLogA(handle, backup2); | 
|  | todo_wine | 
|  | { | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(GetFileAttributesA(backup2) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n"); | 
|  | } | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  | DeleteFileA(backup2); | 
|  | } | 
|  |  | 
|  | static void test_read(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | DWORD count, toread, read, needed; | 
|  | void *buf; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | read = 0xdeadbeef; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(read == 0xdeadbeef, "Expected 'read' parameter to remain unchanged\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | needed = 0xdeadbeef; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(needed == 0xdeadbeef, "Expected 'needed' parameter to remain unchanged\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | /* 'read' and 'needed' are only filled when the needed buffer size is passed back or when the call succeeds */ | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | buf = NULL; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, "Application"); | 
|  |  | 
|  | /* Show that we need the proper dwFlags with a (for the rest) proper call */ | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, 0, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | todo_wine | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  |  | 
|  | /* First check if there are any records (in practice only on Wine: FIXME) */ | 
|  | count = 0; | 
|  | GetNumberOfEventLogRecords(handle, &count); | 
|  | if (!count) | 
|  | { | 
|  | skip("No records in the 'Application' log\n"); | 
|  | CloseEventLog(handle); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Get the buffer size for the first record */ | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); | 
|  | read = needed = 0xdeadbeef; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(read == 0, "Expected no bytes read\n"); | 
|  | ok(needed > sizeof(EVENTLOGRECORD), "Expected the needed buffersize to be bigger than sizeof(EVENTLOGRECORD)\n"); | 
|  | ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | /* Read the first record */ | 
|  | toread = needed; | 
|  | buf = HeapReAlloc(GetProcessHeap(), 0, buf, toread); | 
|  | read = needed = 0xdeadbeef; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, buf, toread, &read, &needed); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(read == toread || | 
|  | broken(read < toread), /* NT4 wants a buffer size way bigger than just 1 record */ | 
|  | "Expected the requested size to be read\n"); | 
|  | ok(needed == 0, "Expected no extra bytes to be read\n"); | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | } | 
|  |  | 
|  | static void test_openbackup(void) | 
|  | { | 
|  | HANDLE handle, handle2, file; | 
|  | DWORD written; | 
|  | const char backup[] = "backup.evt"; | 
|  | const char text[] = "Just some text"; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA(NULL, NULL); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA(NULL, "idontexist.evt"); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA("IDontExist", NULL); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA("IDontExist", "idontexist.evt"); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || | 
|  | GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */ | 
|  | "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError()); | 
|  |  | 
|  | /* Make a backup eventlog to work with */ | 
|  | create_backup(backup); | 
|  |  | 
|  | /* FIXME: Wine stops here */ | 
|  | if (GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES) | 
|  | { | 
|  | skip("We don't have a backup eventlog to work with\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA("IDontExist", backup); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || | 
|  | GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */ | 
|  | "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError()); | 
|  |  | 
|  | /* Empty servername should be read as local server */ | 
|  | handle = OpenBackupEventLogA("", backup); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | /* Can we open that same backup eventlog more than once? */ | 
|  | handle2 = OpenBackupEventLogA(NULL, backup); | 
|  | ok(handle2 != NULL, "Expected a handle\n"); | 
|  | ok(handle2 != handle, "Didn't expect the same handle\n"); | 
|  | CloseEventLog(handle2); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  |  | 
|  | /* Is there any content checking done? */ | 
|  | file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); | 
|  | CloseHandle(file); | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY || | 
|  | GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, /* Vista and Win7 */ | 
|  | "Expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError()); | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  |  | 
|  | file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); | 
|  | WriteFile(file, text, sizeof(text), &written, NULL); | 
|  | CloseHandle(file); | 
|  | SetLastError(0xdeadbeef); | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | ok(handle == NULL, "Didn't expect a handle\n"); | 
|  | ok(GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, "Expected ERROR_EVENTLOG_FILE_CORRUPT, got %d\n", GetLastError()); | 
|  | CloseEventLog(handle); | 
|  | DeleteFileA(backup); | 
|  | } | 
|  |  | 
|  | static void test_clear(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | BOOL ret; | 
|  | const char backup[] = "backup.evt"; | 
|  | const char backup2[] = "backup2.evt"; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(NULL, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | /* Make a backup eventlog to work with */ | 
|  | create_backup(backup); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(NULL, backup); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | handle = OpenBackupEventLogA(NULL, backup); | 
|  | todo_wine | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | /* A real eventlog would fail with ERROR_ALREADY_EXISTS */ | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(handle, backup); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | /* The eventlog service runs under an account that doesn't have the necessary | 
|  | * permissions on the users home directory on a default Vista+ system. | 
|  | */ | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE || | 
|  | GetLastError() == ERROR_ACCESS_DENIED, /* Vista+ */ | 
|  | "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | /* Show that ClearEventLog only works for real eventlogs. */ | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(handle, backup2); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  | ok(GetFileAttributesA(backup2) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(handle, NULL); | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  | todo_wine | 
|  | ok(DeleteFileA(backup), "Could not delete the backup file\n"); | 
|  | } | 
|  |  | 
|  | static const char eventlogsvc[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog"; | 
|  | static const char eventlogname[] = "Wine"; | 
|  | static const char eventsources[][11] = { "WineSrc", "WineSrc1", "WineSrc20", "WineSrc300" }; | 
|  |  | 
|  | static BOOL create_new_eventlog(void) | 
|  | { | 
|  | HKEY key, eventkey; | 
|  | BOOL bret = FALSE; | 
|  | LONG lret; | 
|  | DWORD i; | 
|  |  | 
|  | /* First create our eventlog */ | 
|  | lret = RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key); | 
|  | /* FIXME: Wine stops here */ | 
|  | if (lret != ERROR_SUCCESS) | 
|  | { | 
|  | skip("Could not open the EventLog service registry key\n"); | 
|  | return FALSE; | 
|  | } | 
|  | lret = RegCreateKeyA(key, eventlogname, &eventkey); | 
|  | if (lret != ERROR_SUCCESS) | 
|  | { | 
|  | skip("Could not create the eventlog '%s' registry key\n", eventlogname); | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | /* Create some event sources, the registry value 'Sources' is updated automatically */ | 
|  | for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++) | 
|  | { | 
|  | HKEY srckey; | 
|  |  | 
|  | lret = RegCreateKeyA(eventkey, eventsources[i], &srckey); | 
|  | if (lret != ERROR_SUCCESS) | 
|  | { | 
|  | skip("Could not create the eventsource '%s' registry key\n", eventsources[i]); | 
|  | goto cleanup; | 
|  | } | 
|  | RegFlushKey(srckey); | 
|  | RegCloseKey(srckey); | 
|  | } | 
|  |  | 
|  | bret = TRUE; | 
|  |  | 
|  | /* The flushing of the registry (here and above) gives us some assurance | 
|  | * that we are not to quickly writing events as 'Sources' could still be | 
|  | * not updated. | 
|  | */ | 
|  | RegFlushKey(eventkey); | 
|  | cleanup: | 
|  | RegCloseKey(eventkey); | 
|  | RegCloseKey(key); | 
|  |  | 
|  | return bret; | 
|  | } | 
|  |  | 
|  | static const char *one_string[] = { "First string" }; | 
|  | static const char *two_strings[] = { "First string", "Second string" }; | 
|  | static const struct | 
|  | { | 
|  | const char  *evt_src; | 
|  | WORD         evt_type; | 
|  | WORD         evt_cat; | 
|  | DWORD        evt_id; | 
|  | BOOL         evt_sid; | 
|  | WORD         evt_numstrings; | 
|  | const char **evt_strings; | 
|  | } read_write [] = | 
|  | { | 
|  | { eventlogname,    EVENTLOG_INFORMATION_TYPE, 1, 1,  FALSE, 1, one_string }, | 
|  | { eventsources[0], EVENTLOG_WARNING_TYPE,     1, 2,  FALSE, 0, NULL }, | 
|  | { eventsources[1], EVENTLOG_AUDIT_FAILURE,    1, 3,  FALSE, 2, two_strings }, | 
|  | { eventsources[2], EVENTLOG_ERROR_TYPE,       1, 4,  FALSE, 0, NULL }, | 
|  | { eventsources[3], EVENTLOG_WARNING_TYPE,     1, 5,  FALSE, 1, one_string }, | 
|  | { eventlogname,    EVENTLOG_SUCCESS,          2, 6,  TRUE,  2, two_strings }, | 
|  | { eventsources[0], EVENTLOG_AUDIT_FAILURE,    2, 7,  TRUE,  0, NULL }, | 
|  | { eventsources[1], EVENTLOG_AUDIT_SUCCESS,    2, 8,  TRUE,  2, two_strings }, | 
|  | { eventsources[2], EVENTLOG_WARNING_TYPE,     2, 9,  TRUE,  0, NULL }, | 
|  | { eventsources[3], EVENTLOG_ERROR_TYPE,       2, 10, TRUE,  1, one_string } | 
|  | }; | 
|  |  | 
|  | static void test_readwrite(void) | 
|  | { | 
|  | HANDLE handle; | 
|  | PSID user; | 
|  | DWORD sidsize, count; | 
|  | BOOL ret, sidavailable; | 
|  | BOOL on_vista = FALSE; /* Used to indicate Vista, W2K8 or Win7 */ | 
|  | DWORD i; | 
|  | char *localcomputer = NULL; | 
|  | DWORD size; | 
|  |  | 
|  | if (pCreateWellKnownSid) | 
|  | { | 
|  | sidsize = SECURITY_MAX_SID_SIZE; | 
|  | user = HeapAlloc(GetProcessHeap(), 0, sidsize); | 
|  | SetLastError(0xdeadbeef); | 
|  | pCreateWellKnownSid(WinInteractiveSid, NULL, user, &sidsize); | 
|  | sidavailable = TRUE; | 
|  | } | 
|  | else | 
|  | { | 
|  | win_skip("Skipping some SID related tests\n"); | 
|  | sidavailable = FALSE; | 
|  | user = NULL; | 
|  | } | 
|  |  | 
|  | /* Write an event with an incorrect event type. This will fail on Windows 7 | 
|  | * but succeed on all others, hence it's not part of the struct. | 
|  | */ | 
|  | handle = OpenEventLogA(NULL, eventlogname); | 
|  | if (!handle) | 
|  | { | 
|  | /* Intermittently seen on NT4 when tests are run immediately after boot */ | 
|  | win_skip("Could not get a handle to the eventlog\n"); | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | count = 0xdeadbeef; | 
|  | GetNumberOfEventLogRecords(handle, &count); | 
|  | if (count != 0) | 
|  | { | 
|  | /* Needed for W2K3 without a service pack */ | 
|  | win_skip("We most likely opened the Application eventlog\n"); | 
|  | CloseEventLog(handle); | 
|  | Sleep(2000); | 
|  |  | 
|  | handle = OpenEventLogA(NULL, eventlogname); | 
|  | count = 0xdeadbeef; | 
|  | GetNumberOfEventLogRecords(handle, &count); | 
|  | if (count != 0) | 
|  | { | 
|  | win_skip("We didn't open our new eventlog\n"); | 
|  | CloseEventLog(handle); | 
|  | goto cleanup; | 
|  | } | 
|  | } | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReportEvent(handle, 0x20, 0, 0, NULL, 0, 0, NULL, NULL); | 
|  | if (!ret && GetLastError() == ERROR_CRC) | 
|  | { | 
|  | win_skip("Win7 fails when using incorrect event types\n"); | 
|  | ret = ReportEvent(handle, 0, 0, 0, NULL, 0, 0, NULL, NULL); | 
|  | ok(ret, "Expected success : %d\n", GetLastError()); | 
|  | } | 
|  | else | 
|  | { | 
|  | void *buf; | 
|  | DWORD read, needed = 0; | 
|  | EVENTLOGRECORD *record; | 
|  |  | 
|  | ok(ret, "Expected success : %d\n", GetLastError()); | 
|  |  | 
|  | /* Needed to catch earlier Vista (with no ServicePack for example) */ | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); | 
|  | if (!(ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed)) && | 
|  | GetLastError() == ERROR_INSUFFICIENT_BUFFER) | 
|  | { | 
|  | buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, needed, &read, &needed); | 
|  | } | 
|  | if (ret) | 
|  | { | 
|  | record = (EVENTLOGRECORD *)buf; | 
|  |  | 
|  | /* Vista and W2K8 return EVENTLOG_SUCCESS, Windows versions before return | 
|  | * the written eventtype (0x20 in this case). | 
|  | */ | 
|  | if (record->EventType == EVENTLOG_SUCCESS) | 
|  | on_vista = TRUE; | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  | } | 
|  |  | 
|  | /* This will clear the eventlog. The record numbering for new | 
|  | * events however differs on Vista SP1+. Before Vista the first | 
|  | * event would be numbered 1, on Vista SP1+ it's higher as we already | 
|  | * had at least one event (more in case of multiple test runs without | 
|  | * a reboot). | 
|  | */ | 
|  | ClearEventLogA(handle, NULL); | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | /* Write a bunch of events while using different event sources */ | 
|  | for (i = 0; i < sizeof(read_write)/sizeof(read_write[0]); i++) | 
|  | { | 
|  | DWORD oldest; | 
|  | BOOL run_sidtests = read_write[i].evt_sid & sidavailable; | 
|  |  | 
|  | /* We don't need to use RegisterEventSource to report events */ | 
|  | if (i % 2) | 
|  | handle = OpenEventLogA(NULL, read_write[i].evt_src); | 
|  | else | 
|  | handle = RegisterEventSourceA(NULL, read_write[i].evt_src); | 
|  | ok(handle != NULL, "Expected a handle\n"); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReportEvent(handle, read_write[i].evt_type, read_write[i].evt_cat, | 
|  | read_write[i].evt_id, run_sidtests ? user : NULL, | 
|  | read_write[i].evt_numstrings, 0, read_write[i].evt_strings, NULL); | 
|  | ok(ret, "Expected ReportEvent success : %d\n", GetLastError()); | 
|  |  | 
|  | count = 0xdeadbeef; | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = GetNumberOfEventLogRecords(handle, &count); | 
|  | ok(ret, "Expected GetNumberOfEventLogRecords success : %d\n", GetLastError()); | 
|  | ok(count == (i + 1), "Expected %d records, got %d\n", i + 1, count); | 
|  |  | 
|  | oldest = 0xdeadbeef; | 
|  | ret = GetOldestEventLogRecord(handle, &oldest); | 
|  | ok(ret, "Expected GetOldestEventLogRecord success : %d\n", GetLastError()); | 
|  | ok(oldest == 1 || | 
|  | (oldest > 1 && oldest != 0xdeadbeef), /* Vista SP1+, W2K8 and Win7 */ | 
|  | "Expected oldest to be 1 or higher, got %d\n", oldest); | 
|  | if (oldest > 1 && oldest != 0xdeadbeef) | 
|  | on_vista = TRUE; | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | if (i % 2) | 
|  | ret = CloseEventLog(handle); | 
|  | else | 
|  | ret = DeregisterEventSource(handle); | 
|  | ok(ret, "Expected success : %d\n", GetLastError()); | 
|  | } | 
|  |  | 
|  | handle = OpenEventLogA(NULL, eventlogname); | 
|  | count = 0xdeadbeef; | 
|  | ret = GetNumberOfEventLogRecords(handle, &count); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(count == i, "Expected %d records, got %d\n", i, count); | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | if (count == 0) | 
|  | { | 
|  | skip("No events were written to the eventlog\n"); | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | /* Report only once */ | 
|  | if (on_vista) | 
|  | skip("There is no DWORD alignment enforced for UserSid on Vista, W2K8 or Win7\n"); | 
|  |  | 
|  | if (on_vista && pGetComputerNameExA) | 
|  | { | 
|  | /* New Vista+ behavior */ | 
|  | size = 0; | 
|  | SetLastError(0xdeadbeef); | 
|  | pGetComputerNameExA(ComputerNameDnsFullyQualified, NULL, &size); | 
|  | localcomputer = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | pGetComputerNameExA(ComputerNameDnsFullyQualified, localcomputer, &size); | 
|  | } | 
|  | else | 
|  | { | 
|  | size = MAX_COMPUTERNAME_LENGTH + 1; | 
|  | localcomputer = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | GetComputerNameA(localcomputer, &size); | 
|  | } | 
|  |  | 
|  | /* Read all events from our created eventlog, one by one */ | 
|  | handle = OpenEventLogA(NULL, eventlogname); | 
|  | i = 0; | 
|  | for (;;) | 
|  | { | 
|  | void *buf; | 
|  | DWORD read, needed; | 
|  | EVENTLOGRECORD *record; | 
|  | char *sourcename, *computername; | 
|  | int k; | 
|  | char *ptr; | 
|  | BOOL run_sidtests = read_write[i].evt_sid & sidavailable; | 
|  |  | 
|  | buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD)); | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, sizeof(EVENTLOGRECORD), &read, &needed); | 
|  | if (!ret && GetLastError() == ERROR_HANDLE_EOF) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  | break; | 
|  | } | 
|  | ok(!ret, "Expected failure\n"); | 
|  | ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, | 
|  | "Expected ERROR_INVALID_PARAMETER, got %d\n",GetLastError()); | 
|  |  | 
|  | buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed); | 
|  | ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, | 
|  | 0, buf, needed, &read, &needed); | 
|  | ok(ret, "Expected success: %d\n", GetLastError()); | 
|  |  | 
|  | record = (EVENTLOGRECORD *)buf; | 
|  |  | 
|  | ok(record->Length == read, | 
|  | "Expected %d, got %d\n", read, record->Length); | 
|  | ok(record->Reserved == 0x654c664c, | 
|  | "Expected 0x654c664c, got %d\n", record->Reserved); | 
|  | ok(record->RecordNumber == i + 1 || | 
|  | (on_vista && (record->RecordNumber > i + 1)), | 
|  | "Expected %d or higher, got %d\n", i + 1, record->RecordNumber); | 
|  | ok(record->EventID == read_write[i].evt_id, | 
|  | "Expected %d, got %d\n", read_write[i].evt_id, record->EventID); | 
|  | ok(record->EventType == read_write[i].evt_type, | 
|  | "Expected %d, got %d\n", read_write[i].evt_type, record->EventType); | 
|  | ok(record->NumStrings == read_write[i].evt_numstrings, | 
|  | "Expected %d, got %d\n", read_write[i].evt_numstrings, record->NumStrings); | 
|  | ok(record->EventCategory == read_write[i].evt_cat, | 
|  | "Expected %d, got %d\n", read_write[i].evt_cat, record->EventCategory); | 
|  |  | 
|  | sourcename = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD)); | 
|  | ok(!lstrcmpA(sourcename, read_write[i].evt_src), "Expected '%s', got '%s'\n", | 
|  | read_write[i].evt_src, sourcename); | 
|  |  | 
|  | computername = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1); | 
|  | ok(!lstrcmpiA(computername, localcomputer), "Expected '%s', got '%s'\n", | 
|  | localcomputer, computername); | 
|  |  | 
|  | /* Before Vista, UserSid was aligned on a DWORD boundary. Next to that if | 
|  | * no padding was actually required a 0 DWORD was still used for padding. No | 
|  | * application should be relying on the padding as we are working with offsets | 
|  | * anyway. | 
|  | */ | 
|  |  | 
|  | if (!on_vista) | 
|  | { | 
|  | DWORD calculated_sidoffset = sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1 + lstrlenA(computername) + 1; | 
|  |  | 
|  | /* We are already DWORD aligned, there should still be some padding */ | 
|  | if ((((UINT_PTR)buf + calculated_sidoffset) % sizeof(DWORD)) == 0) | 
|  | ok(*(DWORD *)((BYTE *)buf + calculated_sidoffset) == 0, "Expected 0\n"); | 
|  |  | 
|  | ok((((UINT_PTR)buf + record->UserSidOffset) % sizeof(DWORD)) == 0, "Expected DWORD alignment\n"); | 
|  | } | 
|  |  | 
|  | if (run_sidtests) | 
|  | { | 
|  | ok(record->UserSidLength == sidsize, "Expected %d, got %d\n", sidsize, record->UserSidLength); | 
|  | } | 
|  | else | 
|  | { | 
|  | ok(record->StringOffset == record->UserSidOffset, "Expected offsets to be the same\n"); | 
|  | ok(record->UserSidLength == 0, "Expected 0, got %d\n", record->UserSidLength); | 
|  | } | 
|  |  | 
|  | ok(record->DataLength == 0, "Expected 0, got %d\n", record->DataLength); | 
|  |  | 
|  | ptr = (char *)((BYTE *)buf + record->StringOffset); | 
|  | for (k = 0; k < record->NumStrings; k++) | 
|  | { | 
|  | ok(!lstrcmpA(ptr, two_strings[k]), "Expected '%s', got '%s'\n", two_strings[k], ptr); | 
|  | ptr += lstrlenA(ptr) + 1; | 
|  | } | 
|  |  | 
|  | ok(record->Length == *(DWORD *)((BYTE *)buf + record->Length - sizeof(DWORD)), | 
|  | "Expected the closing DWORD to contain the length of the record\n"); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, buf); | 
|  | i++; | 
|  | } | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | /* Test clearing a real eventlog */ | 
|  | handle = OpenEventLogA(NULL, eventlogname); | 
|  |  | 
|  | SetLastError(0xdeadbeef); | 
|  | ret = ClearEventLogA(handle, NULL); | 
|  | ok(ret, "Expected success\n"); | 
|  |  | 
|  | count = 0xdeadbeef; | 
|  | ret = GetNumberOfEventLogRecords(handle, &count); | 
|  | ok(ret, "Expected success\n"); | 
|  | ok(count == 0, "Expected an empty eventlog, got %d records\n", count); | 
|  |  | 
|  | CloseEventLog(handle); | 
|  |  | 
|  | cleanup: | 
|  | HeapFree(GetProcessHeap(), 0, localcomputer); | 
|  | HeapFree(GetProcessHeap(), 0, user); | 
|  | } | 
|  |  | 
|  | /* Before Vista: | 
|  | * | 
|  | * Creating an eventlog on Windows (via the registry) automatically leads | 
|  | * to creation of a REG_MULTI_SZ named 'Sources'. This value lists all the | 
|  | * potential event sources for this eventlog. 'Sources' is automatically | 
|  | * updated when a new key (aka event source) is created. | 
|  | * | 
|  | * Although the updating of registry keys is almost instantaneously, we | 
|  | * check it after some other tests to assure we are not querying the | 
|  | * registry or file system to quickly. | 
|  | * | 
|  | * NT4 and higher: | 
|  | * | 
|  | * The eventlog file itself is also automatically created, even before we | 
|  | * start writing events. | 
|  | */ | 
|  | static char eventlogfile[MAX_PATH]; | 
|  | static void test_autocreation(void) | 
|  | { | 
|  | HKEY key, eventkey; | 
|  | DWORD type, size; | 
|  | LONG ret; | 
|  | int i; | 
|  | char *p; | 
|  | char sources[sizeof(eventsources)]; | 
|  | char sysdir[MAX_PATH]; | 
|  | void *redir = 0; | 
|  |  | 
|  | RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key); | 
|  | RegOpenKeyA(key, eventlogname, &eventkey); | 
|  |  | 
|  | size = sizeof(sources); | 
|  | sources[0] = 0; | 
|  | ret = RegQueryValueExA(eventkey, "Sources", NULL, &type, (LPBYTE)sources, &size); | 
|  | if (ret == ERROR_SUCCESS) | 
|  | { | 
|  | char sources_verify[sizeof(eventsources)]; | 
|  |  | 
|  | ok(type == REG_MULTI_SZ, "Expected a REG_MULTI_SZ, got %d\n", type); | 
|  |  | 
|  | /* Build the expected string */ | 
|  | memset(sources_verify, 0, sizeof(sources_verify)); | 
|  | p = sources_verify; | 
|  | for (i = sizeof(eventsources)/sizeof(eventsources[0]); i > 0; i--) | 
|  | { | 
|  | lstrcpyA(p, eventsources[i - 1]); | 
|  | p += (lstrlenA(eventsources[i - 1]) + 1); | 
|  | } | 
|  | lstrcpyA(p, eventlogname); | 
|  |  | 
|  | ok(!memcmp(sources, sources_verify, size), | 
|  | "Expected a correct 'Sources' value (size : %d)\n", size); | 
|  | } | 
|  |  | 
|  | RegCloseKey(eventkey); | 
|  | RegCloseKey(key); | 
|  |  | 
|  | /* The directory that holds the eventlog files could be redirected */ | 
|  | if (pWow64DisableWow64FsRedirection) | 
|  | pWow64DisableWow64FsRedirection(&redir); | 
|  |  | 
|  | /* On Windows we also automatically get an eventlog file */ | 
|  | GetSystemDirectoryA(sysdir, sizeof(sysdir)); | 
|  |  | 
|  | /* NT4 - W2K3 */ | 
|  | lstrcpyA(eventlogfile, sysdir); | 
|  | lstrcatA(eventlogfile, "\\config\\"); | 
|  | lstrcatA(eventlogfile, eventlogname); | 
|  | lstrcatA(eventlogfile, ".evt"); | 
|  |  | 
|  | if (GetFileAttributesA(eventlogfile) == INVALID_FILE_ATTRIBUTES) | 
|  | { | 
|  | /* Vista+ */ | 
|  | lstrcpyA(eventlogfile, sysdir); | 
|  | lstrcatA(eventlogfile, "\\winevt\\Logs\\"); | 
|  | lstrcatA(eventlogfile, eventlogname); | 
|  | lstrcatA(eventlogfile, ".evtx"); | 
|  | } | 
|  |  | 
|  | ok(GetFileAttributesA(eventlogfile) != INVALID_FILE_ATTRIBUTES, | 
|  | "Expected an eventlog file\n"); | 
|  |  | 
|  | if (pWow64RevertWow64FsRedirection) | 
|  | pWow64RevertWow64FsRedirection(redir); | 
|  | } | 
|  |  | 
|  | static void cleanup_eventlog(void) | 
|  | { | 
|  | BOOL bret; | 
|  | LONG lret; | 
|  | HKEY key; | 
|  | DWORD i; | 
|  | char winesvc[MAX_PATH]; | 
|  |  | 
|  | /* Delete the registry tree */ | 
|  | lstrcpyA(winesvc, eventlogsvc); | 
|  | lstrcatA(winesvc, "\\"); | 
|  | lstrcatA(winesvc, eventlogname); | 
|  |  | 
|  | RegOpenKeyA(HKEY_LOCAL_MACHINE, winesvc, &key); | 
|  | for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++) | 
|  | RegDeleteKeyA(key, eventsources[i]); | 
|  | RegDeleteValueA(key, "Sources"); | 
|  | RegCloseKey(key); | 
|  | lret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, winesvc); | 
|  | todo_wine | 
|  | ok(lret == ERROR_SUCCESS, "Could not delete the registry tree : %d\n", lret); | 
|  |  | 
|  | /* A handle to the eventlog is locked by services.exe. We can only | 
|  | * delete the eventlog file after reboot. | 
|  | */ | 
|  | bret = MoveFileExA(eventlogfile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); | 
|  | todo_wine | 
|  | ok(bret, "Expected MoveFileEx to succeed: %d\n", GetLastError()); | 
|  | } | 
|  |  | 
|  | START_TEST(eventlog) | 
|  | { | 
|  | SetLastError(0xdeadbeef); | 
|  | CloseEventLog(NULL); | 
|  | if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) | 
|  | { | 
|  | win_skip("Event log functions are not implemented\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | init_function_pointers(); | 
|  |  | 
|  | /* Parameters only */ | 
|  | test_open_close(); | 
|  | test_info(); | 
|  | test_count(); | 
|  | test_oldest(); | 
|  | test_backup(); | 
|  | test_openbackup(); | 
|  | test_read(); | 
|  | test_clear(); | 
|  |  | 
|  | /* Functional tests */ | 
|  | if (create_new_eventlog()) | 
|  | { | 
|  | test_readwrite(); | 
|  | test_autocreation(); | 
|  | cleanup_eventlog(); | 
|  | } | 
|  | } |