Index: uspace/lib/pcut/src/assert.c
===================================================================
--- uspace/lib/pcut/src/assert.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/assert.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -35,4 +35,7 @@
  */
 
+/** We need _BSD_SOURCE because of vsnprintf() when compiling under C89. */
+#define _BSD_SOURCE
+
 #include "internal.h"
 #include <setjmp.h>
@@ -52,19 +55,18 @@
 static int message_buffer_index = 0;
 
-/** Announce that assertion failed.
- *
- * @warning This function may not return.
- *
- * @param fmt printf-style formatting string.
- *
- */
-void pcut_failed_assertion_fmt(const char *fmt, ...) {
+void pcut_failed_assertion_fmt(const char *filename, int line, const char *fmt, ...) {
+	va_list args;
 	char *current_buffer = message_buffer[message_buffer_index];
+	size_t offset = 0;
 	message_buffer_index = (message_buffer_index + 1) % MESSAGE_BUFFER_COUNT;
 
-	va_list args;
-	va_start(args, fmt);
-	vsnprintf(current_buffer, MAX_MESSAGE_LENGTH, fmt, args);
-	va_end(args);
+	snprintf(current_buffer, MAX_MESSAGE_LENGTH, "%s:%d: ", filename, line);
+	offset = pcut_str_size(current_buffer);
+
+	if (offset + 1 < MAX_MESSAGE_LENGTH) {
+		va_start(args, fmt);
+		vsnprintf(current_buffer + offset, MAX_MESSAGE_LENGTH - offset, fmt, args);
+		va_end(args);
+	}
 
 	pcut_failed_assertion(current_buffer);
Index: uspace/lib/pcut/src/internal.h
===================================================================
--- uspace/lib/pcut/src/internal.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/internal.h	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -37,4 +37,28 @@
 #include <stdlib.h>
 
+
+/** @def PCUT_DEBUG(msg, ...)
+ * Debug printing.
+ *
+ * By default, this macro does nothing. Define PCUT_DEBUG_BUILD to
+ * actually print the messages to the console.
+ *
+ * @param msg Printf-like formatting message.
+ * @param ... Extra arguments for printf.
+ */
+#ifdef PCUT_DEBUG_BUILD
+#include <stdio.h>
+#define PCUT_DEBUG_INTERNAL(msg, ...) \
+	fprintf(stderr, "[PCUT %s:%d]: " msg "%s", __FILE__, __LINE__, __VA_ARGS__)
+#define PCUT_DEBUG(...) \
+	PCUT_DEBUG_INTERNAL( \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, this_arg_is_ignored), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, "\n") \
+	)
+#else
+#define PCUT_DEBUG(...) (void)0
+#endif
+
+
 /** Mark a variable as unused. */
 #define PCUT_UNUSED(x) ((void)x)
@@ -63,4 +87,13 @@
 /** Test outcome: test failed unexpectedly. */
 #define TEST_OUTCOME_ERROR 3
+
+
+/*
+ * Use sprintf_s in Windows but only with Microsoft compiler.
+ * Namely, let MinGW use snprintf.
+ */
+#if (defined(__WIN64) || defined(__WIN32) || defined(_WIN32)) && defined(_MSC_VER)
+#define snprintf sprintf_s
+#endif
 
 extern int pcut_run_mode;
@@ -92,4 +125,6 @@
 	/** Initialize the reporting, given all tests. */
 	void (*init)(pcut_item_t *);
+	/** Finalize the reporting. */
+	void (*done)(void);
 	/** Test suite just started. */
 	void (*suite_start)(pcut_item_t *);
@@ -101,6 +136,4 @@
 	void (*test_done)(pcut_item_t *, int, const char *, const char *,
 		const char *);
-	/** Finalize the reporting. */
-	void (*done)(void);
 };
 
@@ -120,4 +153,16 @@
 /* OS-dependent functions. */
 
+/** Hook to execute before test starts.
+ *
+ * Useful for OS-specific preparations prior to launching the actual
+ * test code (i. e. sandboxing the process more etc.).
+ *
+ * This function is not run by the launcher process that only
+ * starts other tests in separate processes.
+ *
+ * @param test The test that is about to be executed.
+ */
+void pcut_hook_before_test(pcut_item_t *test);
+
 /** Tell whether two strings start with the same prefix.
  *
Index: uspace/lib/pcut/src/list.c
===================================================================
--- uspace/lib/pcut/src/list.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/list.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -82,17 +82,19 @@
  */
 static void inline_nested_lists(pcut_item_t *nested) {
+	pcut_item_t *first;
+
 	if (nested->kind != PCUT_KIND_NESTED) {
 		return;
 	}
 
-	if (nested->nested.last == NULL) {
+	if (nested->nested == NULL) {
 		nested->kind = PCUT_KIND_SKIP;
 		return;
 	}
 
-	pcut_item_t *first = pcut_fix_list_get_real_head(nested->nested.last);
-	nested->nested.last->next = nested->next;
+	first = pcut_fix_list_get_real_head(nested->nested);
+	nested->nested->next = nested->next;
 	if (nested->next != NULL) {
-		nested->next->previous = nested->nested.last;
+		nested->next->previous = nested->nested;
 	}
 	nested->next = first;
@@ -107,10 +109,14 @@
  */
 static void set_ids(pcut_item_t *first) {
+	int id = 1;
+	pcut_item_t *it;
+
 	assert(first != NULL);
-	int id = 1;
+
 	if (first->kind == PCUT_KIND_SKIP) {
 		first = pcut_get_real_next(first);
 	}
-	for (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
 		it->id = id;
 		id++;
@@ -126,13 +132,19 @@
  */
 static void detect_skipped_tests(pcut_item_t *first) {
+	pcut_item_t *it;
+
 	assert(first != NULL);
 	if (first->kind == PCUT_KIND_SKIP) {
 		first = pcut_get_real_next(first);
 	}
-	for (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
+		pcut_extra_t *extras;
+
 		if (it->kind != PCUT_KIND_TEST) {
 			continue;
 		}
-		pcut_extra_t *extras = it->test.extras;
+
+		extras = it->extras;
 		while (extras->type != PCUT_EXTRA_LAST) {
 			if (extras->type == PCUT_EXTRA_SKIP) {
@@ -156,11 +168,12 @@
  */
 pcut_item_t *pcut_fix_list_get_real_head(pcut_item_t *last) {
+	pcut_item_t *next, *it;
+
 	last->next = NULL;
 
 	inline_nested_lists(last);
 
-	pcut_item_t *next = last;
-
-	pcut_item_t *it = last->previous;
+	next = last;
+	it = last->previous;
 	while (it != NULL) {
 		it->next = next;
Index: uspace/lib/pcut/src/main.c
===================================================================
--- uspace/lib/pcut/src/main.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/main.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -41,4 +41,12 @@
 int pcut_run_mode = PCUT_RUN_MODE_FORKING;
 
+/** Empty list to bypass special handling for NULL. */
+static pcut_main_extra_t empty_main_extra[] = {
+	PCUT_MAIN_EXTRA_SET_LAST
+};
+
+/** Helper for iteration over main extras. */
+#define FOR_EACH_MAIN_EXTRA(extras, it) \
+	for (it = extras; it->type != PCUT_MAIN_EXTRA_LAST; it++)
 
 /** Checks whether the argument is an option followed by a number.
@@ -54,6 +62,5 @@
 		return 0;
 	}
-	int val = pcut_str_to_int(arg + opt_len);
-	*value = val;
+	*value = pcut_str_to_int(arg + opt_len);
 	return 1;
 }
@@ -85,4 +92,7 @@
  */
 static void run_suite(pcut_item_t *suite, pcut_item_t **last, const char *prog_path) {
+	int is_first_test = 1;
+	int total_count = 0;
+
 	pcut_item_t *it = pcut_get_real_next(suite);
 	if ((it == NULL) || (it->kind == PCUT_KIND_TESTSUITE)) {
@@ -90,7 +100,4 @@
 	}
 
-	int is_first_test = 1;
-	int total_count = 0;
-
 	for (; it != NULL; it = pcut_get_real_next(it)) {
 		if (it->kind == PCUT_KIND_TESTSUITE) {
@@ -135,15 +142,16 @@
 static void set_setup_teardown_callbacks(pcut_item_t *first) {
 	pcut_item_t *active_suite = NULL;
-	for (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+	pcut_item_t *it;
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
 		if (it->kind == PCUT_KIND_TESTSUITE) {
 			active_suite = it;
 		} else if (it->kind == PCUT_KIND_SETUP) {
 			if (active_suite != NULL) {
-				active_suite->suite.setup = it->setup.func;
+				active_suite->setup_func = it->setup_func;
 			}
 			it->kind = PCUT_KIND_SKIP;
 		} else if (it->kind == PCUT_KIND_TEARDOWN) {
 			if (active_suite != NULL) {
-				active_suite->suite.teardown = it->setup.func;
+				active_suite->teardown_func = it->teardown_func;
 			}
 			it->kind = PCUT_KIND_SKIP;
@@ -166,9 +174,25 @@
 int pcut_main(pcut_item_t *last, int argc, char *argv[]) {
 	pcut_item_t *items = pcut_fix_list_get_real_head(last);
+	pcut_item_t *it;
+	pcut_main_extra_t *main_extras = last->main_extras;
+	pcut_main_extra_t *main_extras_it;
 
 	int run_only_suite = -1;
 	int run_only_test = -1;
 
+	if (main_extras == NULL) {
+		main_extras = empty_main_extra;
+	}
+
 	pcut_report_register_handler(&pcut_report_tap);
+
+	FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_REPORT_XML) {
+			pcut_report_register_handler(&pcut_report_xml);
+		}
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_PREINIT_HOOK) {
+			main_extras_it->preinit_hook(&argc, &argv);
+		}
+	}
 
 	if (argc > 1) {
@@ -195,4 +219,10 @@
 	set_setup_teardown_callbacks(items);
 
+	FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_INIT_HOOK) {
+			main_extras_it->init_hook();
+		}
+	}
+
 	PCUT_DEBUG("run_only_suite = %d   run_only_test = %d", run_only_suite, run_only_test);
 
@@ -218,4 +248,5 @@
 
 	if (run_only_test > 0) {
+		int rc;
 		pcut_item_t *test = pcut_find_by_id(items, run_only_test);
 		if (test == NULL) {
@@ -228,5 +259,4 @@
 		}
 
-		int rc;
 		if (pcut_run_mode == PCUT_RUN_MODE_SINGLE) {
 			rc = pcut_run_test_single(test);
@@ -241,5 +271,5 @@
 	pcut_report_init(items);
 
-	pcut_item_t *it = items;
+	it = items;
 	while (it != NULL) {
 		if (it->kind == PCUT_KIND_TESTSUITE) {
Index: uspace/lib/pcut/src/os/generic.c
===================================================================
--- uspace/lib/pcut/src/os/generic.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/os/generic.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -33,4 +33,5 @@
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <errno.h>
@@ -50,5 +51,5 @@
 /* Format the command to launch a test according to OS we are running on. */
 
-#if defined(__WIN64) || defined(__WIN32)
+#if defined(__WIN64) || defined(__WIN32) || defined(_WIN32)
 #include <process.h>
 
@@ -108,17 +109,25 @@
  */
 void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	int rc;
+	FILE *tempfile;
+	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
+	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
+
 	before_test_start(test);
 
-	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
 	FORMAT_TEMP_FILENAME(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1);
-
-	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
 	FORMAT_COMMAND(command, PCUT_COMMAND_LINE_BUFFER_SIZE - 1,
 		self_path, (test)->id, tempfile_name);
+	
+	PCUT_DEBUG("Will execute <%s> (temp file <%s>) with system().",
+		command, tempfile_name);
 
-	int rc = system(command);
+	rc = system(command);
+
+	PCUT_DEBUG("system() returned 0x%04X", rc);
+
 	rc = convert_wait_status_to_outcome(rc);
 
-	FILE *tempfile = fopen(tempfile_name, "rb");
+	tempfile = fopen(tempfile_name, "rb");
 	if (tempfile == NULL) {
 		pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to open temporary file.", NULL, NULL);
@@ -133,2 +142,8 @@
 }
 
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
+
Index: uspace/lib/pcut/src/os/helenos.c
===================================================================
--- uspace/lib/pcut/src/os/helenos.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/os/helenos.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -185,5 +185,6 @@
 	int status = TEST_OUTCOME_PASS;
 
-	int rc = task_spawnvf(&test_task_id, self_path, arguments, files);
+	task_wait_t test_task_wait;
+	int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments, files);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -203,5 +204,5 @@
 	task_exit_t task_exit;
 	int task_retval;
-	rc = task_wait(test_task_id, &task_exit, &task_retval);
+	rc = task_wait(&test_task_wait, &task_exit, &task_retval);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -227,2 +228,8 @@
 	pcut_report_test_done_unparsed(test, status, extra_output_buffer, OUTPUT_BUFFER_SIZE);
 }
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
Index: uspace/lib/pcut/src/os/unix.c
===================================================================
--- uspace/lib/pcut/src/os/unix.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/os/unix.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -32,6 +32,8 @@
  */
 
-/** We need _POSX_SOURCE because of kill(). */
+/** We need _POSIX_SOURCE because of kill(). */
 #define _POSIX_SOURCE
+/** We need _BSD_SOURCE because of snprintf() when compiling under C89. */
+#define _BSD_SOURCE
 #include <stdlib.h>
 #include <unistd.h>
@@ -137,11 +139,14 @@
  */
 void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	int link_stdout[2], link_stderr[2];
+	int rc, status;
+	size_t stderr_size;
+
 	PCUT_UNUSED(self_path);
 
 	before_test_start(test);
 
-	int link_stdout[2], link_stderr[2];
-
-	int rc = pipe(link_stdout);
+
+	rc = pipe(link_stdout);
 	if (rc == -1) {
 		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
@@ -184,8 +189,7 @@
 	alarm(pcut_get_test_timeout(test));
 
-	size_t stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
+	stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
 	read_all(link_stdout[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1 - stderr_size);
 
-	int status;
 	wait(&status);
 	alarm(0);
@@ -204,2 +208,9 @@
 	pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
 }
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
+
Index: uspace/lib/pcut/src/os/windows.c
===================================================================
--- uspace/lib/pcut/src/os/windows.c	(revision c85a57f12649ef695469bac41ca451943f828502)
+++ uspace/lib/pcut/src/os/windows.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Windows-specific functions for test execution via the popen() system call.
+ */
+
+/*
+ * Code inspired by Creating a Child Process with Redirected Input and Output:
+ * http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx
+ */
+
+#include "../internal.h"
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <strsafe.h>
+
+
+/** Maximum size of stdout we are able to capture. */
+#define OUTPUT_BUFFER_SIZE 8192
+
+/** Maximum command-line length. */
+#define PCUT_COMMAND_LINE_BUFFER_SIZE 256
+
+/** Buffer for assertion and other error messages. */
+static char error_message_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Buffer for stdout from the test. */
+static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Prepare for a new test.
+ *
+ * @param test Test that is about to be run.
+ */
+static void before_test_start(pcut_item_t *test) {
+	pcut_report_test_start(test);
+
+	memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
+	memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
+}
+
+/** Report that a certain function failed.
+ *
+ * @param test Current test.
+ * @param failed_function_name Name of the failed function.
+ */
+static void report_func_fail(pcut_item_t *test, const char *failed_function_name) {
+	/* TODO: get error description. */
+	sprintf_s(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
+		"%s failed: %s.", failed_function_name, "unknown reason");
+	pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
+}
+
+/** Read full buffer from given file descriptor.
+ *
+ * This function exists to overcome the possibility that read() may
+ * not fill the full length of the provided buffer even when EOF is
+ * not reached.
+ *
+ * @param fd Opened file descriptor.
+ * @param buffer Buffer to store data into.
+ * @param buffer_size Size of the @p buffer in bytes.
+ * @return Number of actually read bytes.
+ */
+static size_t read_all(HANDLE fd, char *buffer, size_t buffer_size) {
+	DWORD actually_read;
+	char *buffer_start = buffer;
+	BOOL okay = FALSE;
+
+	do {
+		okay = ReadFile(fd, buffer, buffer_size, &actually_read, NULL);
+		if (!okay) {
+			break;
+		}
+		if (actually_read > 0) {
+			buffer += actually_read;
+			buffer_size -= actually_read;
+			if (buffer_size == 0) {
+				break;
+			}
+		}
+	} while (actually_read > 0);
+	if (buffer_start != buffer) {
+		if (*(buffer - 1) == 10) {
+			*(buffer - 1) = 0;
+			buffer--;
+		}
+	}
+	return buffer - buffer_start;
+}
+
+struct test_output_data {
+	HANDLE pipe_stdout;
+	HANDLE pipe_stderr;
+	char *output_buffer;
+	size_t output_buffer_size;
+};
+
+static DWORD WINAPI read_test_output_on_background(LPVOID test_output_data_ptr) {
+	size_t stderr_size = 0;
+	struct test_output_data *test_output_data = (struct test_output_data *) test_output_data_ptr;
+
+	stderr_size = read_all(test_output_data->pipe_stderr,
+		test_output_data->output_buffer,
+		test_output_data->output_buffer_size - 1);
+	read_all(test_output_data->pipe_stdout,
+		test_output_data->output_buffer,
+		test_output_data->output_buffer_size - 1 - stderr_size);
+
+	return 0;
+}
+
+/** Run the test as a new process and report the result.
+ *
+ * @param self_path Path to itself, that is to current binary.
+ * @param test Test to be run.
+ */
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	/* TODO: clean-up if something goes wrong "in the middle" */
+	BOOL okay = FALSE;
+	DWORD rc;
+	int outcome;
+	int timed_out;
+	int time_out_millis;
+	SECURITY_ATTRIBUTES security_attributes;
+	HANDLE link_stdout[2] = { NULL, NULL };
+	HANDLE link_stderr[2] = { NULL, NULL };
+	HANDLE link_stdin[2] = { NULL, NULL };
+	PROCESS_INFORMATION process_info;
+	STARTUPINFO start_info;
+	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
+	struct test_output_data test_output_data;
+	HANDLE test_output_thread_reader;
+
+
+	before_test_start(test);
+
+	/* Pipe handles are inherited. */
+	security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+	security_attributes.bInheritHandle = TRUE;
+	security_attributes.lpSecurityDescriptor = NULL;
+
+	/* Create pipe for stdout, make sure it is not inherited. */
+	okay = CreatePipe(&link_stdout[0], &link_stdout[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stdout */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stdout[0], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stdout */)");
+		return;
+	}
+
+	/* Create pipe for stderr, make sure it is not inherited. */
+	okay = CreatePipe(&link_stderr[0], &link_stderr[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stderr */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stderr[0], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stderr */)");
+		return;
+	}
+
+	/* Create pipe for stdin, make sure it is not inherited. */
+	okay = CreatePipe(&link_stdin[0], &link_stdin[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stdin */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stdin[1], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stdin */)");
+		return;
+	}
+
+	/* Prepare information for the child process. */
+	ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
+	ZeroMemory(&start_info, sizeof(STARTUPINFO));
+	start_info.cb = sizeof(STARTUPINFO);
+	start_info.hStdError = link_stderr[1];
+	start_info.hStdOutput = link_stdout[1];
+	start_info.hStdInput = link_stdin[0];
+	start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+	/* Format the command line. */
+	sprintf_s(command, PCUT_COMMAND_LINE_BUFFER_SIZE - 1,
+		"\"%s\" -t%d", self_path, test->id);
+
+	/* Run the process. */
+	okay = CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL,
+		&start_info, &process_info);
+
+	if (!okay) {
+		report_func_fail(test, "CreateProcess()");
+		return;
+	}
+
+	// FIXME: kill the process on error
+
+	/* Close handles to the first thread. */
+	CloseHandle(process_info.hThread);
+
+	/* Close the other ends of the pipes. */
+	okay = CloseHandle(link_stdout[1]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stdout */)");
+		return;
+	}
+	okay = CloseHandle(link_stderr[1]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stderr */)");
+		return;
+	}
+	okay = CloseHandle(link_stdin[0]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stdin */)");
+		return;
+	}
+
+	/*
+	 * Read data from stdout and stderr.
+	 * We need to do this in a separate thread to allow the
+	 * time-out to work correctly.
+	 * Probably, this can be done with asynchronous I/O but
+	 * this works for now pretty well.
+	 */
+	test_output_data.pipe_stderr = link_stderr[0];
+	test_output_data.pipe_stdout = link_stdout[0];
+	test_output_data.output_buffer = extra_output_buffer;
+	test_output_data.output_buffer_size = OUTPUT_BUFFER_SIZE;
+
+	test_output_thread_reader = CreateThread(NULL, 0,
+		read_test_output_on_background, &test_output_data,
+		0, NULL);
+
+	if (test_output_thread_reader == NULL) {
+		report_func_fail(test, "CreateThread(/* read test stdout */)");
+		return;
+	}
+
+	/* Wait for the process to terminate. */
+	timed_out = 0;
+	time_out_millis = pcut_get_test_timeout(test) * 1000;
+	rc = WaitForSingleObject(process_info.hProcess, time_out_millis);
+	PCUT_DEBUG("Waiting for test %s (%dms) returned %d.", test->name, time_out_millis, rc);
+	if (rc == WAIT_TIMEOUT) {
+		/* We timed-out: kill the process and wait for its termination again. */
+		timed_out = 1;
+		okay = TerminateProcess(process_info.hProcess, 5);
+		if (!okay) {
+			report_func_fail(test, "TerminateProcess(/* PROCESS_INFORMATION.hProcess */)");
+			return;
+		}
+		rc = WaitForSingleObject(process_info.hProcess, INFINITE);
+	}
+	if (rc != WAIT_OBJECT_0) {
+		report_func_fail(test, "WaitForSingleObject(/* PROCESS_INFORMATION.hProcess */)");
+		return;
+	}
+
+	/* Get the return code and convert it to outcome. */
+	okay = GetExitCodeProcess(process_info.hProcess, &rc);
+	if (!okay) {
+		report_func_fail(test, "GetExitCodeProcess()");
+		return;
+	}
+
+	if (rc == 0) {
+		outcome = TEST_OUTCOME_PASS;
+	} else if ((rc > 0) && (rc < 10) && !timed_out) {
+		outcome = TEST_OUTCOME_FAIL;
+	} else {
+		outcome = TEST_OUTCOME_ERROR;
+	}
+
+	/* Wait for the reader thread (shall be terminated by now). */
+	rc = WaitForSingleObject(test_output_thread_reader, INFINITE);
+	if (rc != WAIT_OBJECT_0) {
+		report_func_fail(test, "WaitForSingleObject(/* stdout reader thread */)");
+		return;
+	}
+
+	pcut_report_test_done_unparsed(test, outcome, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+}
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/*
+	 * Prevent displaying the dialog informing the user that the
+	 * program unexpectedly failed.
+	 */
+	SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+}
Index: uspace/lib/pcut/src/preproc.c
===================================================================
--- uspace/lib/pcut/src/preproc.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/preproc.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -91,5 +91,5 @@
 }
 
-int main() {
+int main(int argc, char *argv[]) {
 	FILE *input = stdin;
 	FILE *output = stdout;
@@ -98,5 +98,11 @@
 	identifier_t last_identifier;
 
+	/* Unused parameters. */
+	(void) argc;
+	(void) argv;
+
 	while (1) {
+		int current_char_denotes_identifier;
+
 		int current_char = fgetc(input);
 		if (current_char == EOF) {
@@ -104,5 +110,5 @@
 		}
 
-		int current_char_denotes_identifier = is_identifier_char(current_char, last_char_was_identifier);
+		current_char_denotes_identifier = is_identifier_char(current_char, last_char_was_identifier);
 		if (current_char_denotes_identifier) {
 			if (!last_char_was_identifier) {
Index: uspace/lib/pcut/src/print.c
===================================================================
--- uspace/lib/pcut/src/print.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/print.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -48,8 +48,8 @@
 		switch (it->kind) {
 		case PCUT_KIND_TEST:
-			printf("TEST %s (%p)\n", it->test.name, it->test.func);
+			printf("TEST %s\n", it->name);
 			break;
 		case PCUT_KIND_TESTSUITE:
-			printf("SUITE %s\n", it->suite.name);
+			printf("SUITE %s\n", it->name);
 			break;
 		case PCUT_KIND_SKIP:
@@ -72,11 +72,12 @@
  */
 void pcut_print_tests(pcut_item_t *first) {
-	for (pcut_item_t *it = pcut_get_real(first); it != NULL; it = pcut_get_real_next(it)) {
+	pcut_item_t *it;
+	for (it = pcut_get_real(first); it != NULL; it = pcut_get_real_next(it)) {
 		switch (it->kind) {
 		case PCUT_KIND_TESTSUITE:
-			printf("  Suite `%s' [%d]\n", it->suite.name, it->id);
+			printf("  Suite `%s' [%d]\n", it->name, it->id);
 			break;
 		case PCUT_KIND_TEST:
-			printf("    Test `%s' [%d]\n", it->test.name, it->id);
+			printf("    Test `%s' [%d]\n", it->name, it->id);
 			break;
 		default:
Index: uspace/lib/pcut/src/report/report.c
===================================================================
--- uspace/lib/pcut/src/report/report.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/report/report.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -44,7 +44,15 @@
  *
  * @param op Operation to be called on the pcut_report_ops_t.
+ * @param ... Arguments to the operation.
  */
 #define REPORT_CALL(op, ...) \
 	if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op(__VA_ARGS__)
+
+/** Call a report function if it is available.
+ *
+ * @param op Operation to be called on the pcut_report_ops_t.
+ */
+#define REPORT_CALL_NO_ARGS(op) \
+		if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op()
 
 /** Print error message.
@@ -94,9 +102,11 @@
 	/* Ensure that we do not read past the full_output. */
 	if (full_output[full_output_size - 1] != 0) {
-		// FIXME: can this happen?
+		/* FIXME: can this happen? */
 		return;
 	}
 
 	while (1) {
+		size_t message_length;
+
 		/* First of all, count number of zero bytes before the text. */
 		size_t cont_zeros_count = 0;
@@ -111,10 +121,10 @@
 
 		/* Determine the length of the text after the zeros. */
-		size_t message_length = pcut_str_size(full_output);
+		message_length = pcut_str_size(full_output);
 
 		if (cont_zeros_count < 2) {
 			/* Okay, standard I/O. */
 			if (message_length > stdio_buffer_size) {
-				// TODO: handle gracefully
+				/* TODO: handle gracefully */
 				return;
 			}
@@ -125,5 +135,5 @@
 			/* Error message. */
 			if (message_length > error_buffer_size) {
-				// TODO: handle gracefully
+				/* TODO: handle gracefully */
 				return;
 			}
@@ -213,6 +223,6 @@
  *
  */
-void pcut_report_done() {
-	REPORT_CALL(done);
-}
-
+void pcut_report_done(void) {
+	REPORT_CALL_NO_ARGS(done);
+}
+
Index: uspace/lib/pcut/src/report/tap.c
===================================================================
--- uspace/lib/pcut/src/report/tap.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/report/tap.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -67,5 +67,5 @@
 	failed_tests_in_suite = 0;
 
-	printf("#> Starting suite %s.\n", suite->suite.name);
+	printf("#> Starting suite %s.\n", suite->name);
 }
 
@@ -76,5 +76,5 @@
 static void tap_suite_done(pcut_item_t *suite) {
 	printf("#> Finished suite %s (failed %d of %d).\n",
-			suite->suite.name, failed_tests_in_suite, tests_in_suite);
+			suite->name, failed_tests_in_suite, tests_in_suite);
 }
 
@@ -98,8 +98,9 @@
  */
 static void print_by_lines(const char *message, const char *prefix) {
+	char *next_line_start;
 	if ((message == NULL) || (message[0] == 0)) {
 		return;
 	}
-	char *next_line_start = pcut_str_find_char(message, '\n');
+	next_line_start = pcut_str_find_char(message, '\n');
 	while (next_line_start != NULL) {
 		next_line_start[0] = 0;
@@ -124,5 +125,7 @@
 		const char *error_message, const char *teardown_error_message,
 		const char *extra_output) {
-	const char *test_name = test->test.name;
+	const char *test_name = test->name;
+	const char *status_str = NULL;
+	const char *fail_error_str = NULL;
 
 	if (outcome != TEST_OUTCOME_PASS) {
@@ -130,6 +133,4 @@
 	}
 
-	const char *status_str = NULL;
-	const char *fail_error_str = NULL;
 	switch (outcome) {
 	case TEST_OUTCOME_PASS:
@@ -158,14 +159,11 @@
 
 /** Report testing done. */
-static void tap_done() {
+static void tap_done(void) {
 }
 
 
 pcut_report_ops_t pcut_report_tap = {
-	.init = tap_init,
-	.done = tap_done,
-	.suite_start = tap_suite_start,
-	.suite_done = tap_suite_done,
-	.test_start = tap_test_start,
-	.test_done = tap_test_done
+	tap_init, tap_done,
+	tap_suite_start, tap_suite_done,
+	tap_test_start, tap_test_done
 };
Index: uspace/lib/pcut/src/report/xml.c
===================================================================
--- uspace/lib/pcut/src/report/xml.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/report/xml.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -53,9 +53,8 @@
  */
 static void xml_init(pcut_item_t *all_items) {
-	printf("<?xml version=\"1.0\"?>\n");
-
 	int tests_total = pcut_count_tests(all_items);
 	test_counter = 0;
 
+	printf("<?xml version=\"1.0\"?>\n");
 	printf("<report tests-total=\"%d\">\n", tests_total);
 }
@@ -69,5 +68,5 @@
 	failed_tests_in_suite = 0;
 
-	printf("\t<suite name=\"%s\">\n", suite->suite.name);
+	printf("\t<suite name=\"%s\">\n", suite->name);
 }
 
@@ -77,5 +76,5 @@
  */
 static void xml_suite_done(pcut_item_t *suite) {
-	printf("\t</suite><!-- %s: %d / %d -->\n", suite->suite.name,
+	printf("\t</suite><!-- %s: %d / %d -->\n", suite->name,
 		failed_tests_in_suite, tests_in_suite);
 }
@@ -100,4 +99,6 @@
  */
 static void print_by_lines(const char *message, const char *element_name) {
+	char *next_line_start;
+
 	if ((message == NULL) || (message[0] == 0)) {
 		return;
@@ -106,5 +107,5 @@
 	printf("\t\t\t<%s><![CDATA[", element_name);
 
-	char *next_line_start = pcut_str_find_char(message, '\n');
+	next_line_start = pcut_str_find_char(message, '\n');
 	while (next_line_start != NULL) {
 		next_line_start[0] = 0;
@@ -131,5 +132,6 @@
 		const char *error_message, const char *teardown_error_message,
 		const char *extra_output) {
-	const char *test_name = test->test.name;
+	const char *test_name = test->name;
+	const char *status_str = NULL;
 
 	if (outcome != TEST_OUTCOME_PASS) {
@@ -137,5 +139,4 @@
 	}
 
-	const char *status_str = NULL;
 	switch (outcome) {
 	case TEST_OUTCOME_PASS:
@@ -165,5 +166,5 @@
 
 /** Report testing done. */
-static void xml_done() {
+static void xml_done(void) {
 	printf("</report>\n");
 }
@@ -171,9 +172,6 @@
 
 pcut_report_ops_t pcut_report_xml = {
-	.init = xml_init,
-	.done = xml_done,
-	.suite_start = xml_suite_start,
-	.suite_done = xml_suite_done,
-	.test_start = xml_test_start,
-	.test_done = xml_test_done
+	xml_init, xml_done,
+	xml_suite_start, xml_suite_done,
+	xml_test_start, xml_test_done
 };
Index: uspace/lib/pcut/src/run.c
===================================================================
--- uspace/lib/pcut/src/run.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/run.c	(revision c85a57f12649ef695469bac41ca451943f828502)
@@ -70,15 +70,19 @@
 
 /** A NULL-like suite. */
-static pcut_item_t default_suite = {
-	.kind = PCUT_KIND_TESTSUITE,
-	.id = -1,
-	.previous = NULL,
-	.next = NULL,
-	.suite = {
-		.name = "Default",
-		.setup = NULL,
-		.teardown = NULL
-	}
-};
+static pcut_item_t default_suite;
+static int default_suite_initialized = 0;
+
+static void init_default_suite_when_needed() {
+	if (default_suite_initialized) {
+		return;
+	}
+	default_suite.id = -1;
+	default_suite.kind = PCUT_KIND_TESTSUITE;
+	default_suite.previous = NULL;
+	default_suite.next = NULL;
+	default_suite.name = "Default";
+	default_suite.setup_func = NULL;
+	default_suite.teardown_func = NULL;
+}
 
 /** Find the suite given test belongs to.
@@ -94,4 +98,5 @@
 		it = it->previous;
 	}
+	init_default_suite_when_needed();
 	return &default_suite;
 }
@@ -115,4 +120,6 @@
  */
 static void leave_test(int outcome) {
+	PCUT_DEBUG("leave_test(outcome=%d), will_exit=%s", outcome,
+		leave_means_exit ? "yes" : "no");
 	if (leave_means_exit) {
 		exit(outcome);
@@ -145,5 +152,5 @@
 		execute_teardown_on_failure = 0;
 		prev_message = message;
-		run_setup_teardown(current_suite->suite.teardown);
+		run_setup_teardown(current_suite->teardown_func);
 
 		/* Tear-down was okay. */
@@ -189,4 +196,6 @@
 	current_test = test;
 
+	pcut_hook_before_test(test);
+
 	/*
 	 * If anything goes wrong, execute the tear-down function
@@ -198,5 +207,5 @@
 	 * Run the set-up function.
 	 */
-	run_setup_teardown(current_suite->suite.setup);
+	run_setup_teardown(current_suite->setup_func);
 
 	/*
@@ -204,5 +213,5 @@
 	 * the actual test.
 	 */
-	test->test.func();
+	test->test_func();
 
 	/*
@@ -211,5 +220,5 @@
 	 */
 	execute_teardown_on_failure = 0;
-	run_setup_teardown(current_suite->suite.teardown);
+	run_setup_teardown(current_suite->teardown_func);
 
 	/*
@@ -234,9 +243,11 @@
  */
 int pcut_run_test_forked(pcut_item_t *test) {
+	int rc;
+
 	report_test_result = 0;
 	print_test_error = 1;
 	leave_means_exit = 1;
 
-	int rc = run_test(test);
+	rc = run_test(test);
 
 	current_test = NULL;
@@ -255,9 +266,11 @@
  */
 int pcut_run_test_single(pcut_item_t *test) {
+	int rc;
+
 	report_test_result = 1;
 	print_test_error = 0;
 	leave_means_exit = 0;
 
-	int rc = run_test(test);
+	rc = run_test(test);
 
 	current_test = NULL;
@@ -273,9 +286,8 @@
  */
 int pcut_get_test_timeout(pcut_item_t *test) {
-	PCUT_UNUSED(test);
-
 	int timeout = PCUT_DEFAULT_TEST_TIMEOUT;
-
-	pcut_extra_t *extras = test->test.extras;
+	pcut_extra_t *extras = test->extras;
+
+
 	while (extras->type != PCUT_EXTRA_LAST) {
 		if (extras->type == PCUT_EXTRA_TIMEOUT) {
