diff --git a/Makefile.am b/Makefile.am
index ff0de9f8..2ce79ff1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,10 +11,15 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch]
 # Preprocessor flags.
 AM_CPPFLAGS += @XOPEN_DEFINES@ \
 	-DTMUX_VERSION='"@VERSION@"' \
-	-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \
 	-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
 	-DTMUX_TERM='"@DEFAULT_TERM@"'
 
+AM_CPPFLAGS += -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"'
+
+if TARGET_WIN32
+AM_CPPFLAGS += -DTMUX_CONF_WIN32='"/c/ProgramData/tmux/tmux.conf:~/.tmux.conf:$$LOCALAPPDATA/tmux/tmux.conf"'
+endif
+
 # Additional object files.
 LDADD = $(LIBOBJS)
 
@@ -67,7 +72,7 @@ AM_CPPFLAGS += -D_BSD_SOURCE
 endif
 
 # Set flags for Cygwin.
-if IS_CYGWIN
+if TARGET_WIN32
 AM_CPPFLAGS += -DTMUX_SOCK_PERM=0
 endif
 
@@ -227,6 +232,12 @@ if ENABLE_SIXEL
 dist_tmux_SOURCES += image.c image-sixel.c
 endif
 
+# Windows-specific support.
+if TARGET_WIN32
+dist_tmux_SOURCES += osdep-win32.c osdep-win32-cpp.cpp
+LDADD += -lole32 -loleaut32 -lwbemuuid
+endif
+
 if NEED_FUZZING
 check_PROGRAMS = fuzz/input-fuzzer
 fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
diff --git a/compat.h b/compat.h
index 93928603..fa20d597 100644
--- a/compat.h
+++ b/compat.h
@@ -77,6 +77,11 @@
 #define __weak __attribute__ ((__weak__))
 #endif
 
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
+#define WIN32_PLATFORM
+#define TTY_OVER_SOCKET
+#endif
+
 #ifndef ECHOPRT
 #define ECHOPRT 0
 #endif
@@ -106,10 +111,6 @@ void	warnx(const char *, ...);
 #define _PATH_BSHELL	"/bin/sh"
 #endif
 
-#ifndef _PATH_TMP
-#define _PATH_TMP	"/tmp/"
-#endif
-
 #ifndef _PATH_DEVNULL
 #define _PATH_DEVNULL	"/dev/null"
 #endif
@@ -479,4 +480,49 @@ int	BSDgetopt(int, char *const *, const char *);
 #define optreset           BSDoptreset
 #define optarg             BSDoptarg
 
+#ifndef WIN32_PLATFORM
+
+#ifndef TMUX_CONF_WIN32
+#define TMUX_CONF_WIN32 "/c/ProgramData/tmux/tmux.conf:~/.tmux.conf"
+#endif
+
+#define SHELL_CMD_SWITCH(shell) "-c"
+#define TMPDIR() "/tmp/"
+
+#ifndef TMUX_SOCK
+#define TMUX_SOCK "$TMUX_TMPDIR:" TMPDIR
+#endif
+
+#define TMPFILE_TEMPLATE() TMPDIR() "tmux.XXXXXXXX"
+
+#define GETENV_HOME()  getenv("HOME")
+#define GETENV_SHELL() getenv("SHELL")
+
+#define TMUX_CONF_SEARCH_PATH() TMUX_CONF
+
+#else
+
+void		win32_setenv_shell(void);
+const char	*win32_get_tmpdir(void);
+const char	*win32_get_tmpfile_template(void);
+const char	*win32_get_socket_dir_search_path(void);
+const char	*win32_get_conf_search_path(void);
+const char	*win32_get_shell_cmd_switch(const char *);
+
+#define SHELL_CMD_SWITCH(shell) win32_get_shell_cmd_switch(shell)
+#define TMPDIR() win32_get_tmpdir()
+
+#ifndef TMUX_SOCK
+#define TMUX_SOCK win32_get_socket_dir_search_path()
+#endif
+
+#define TMPFILE_TEMPLATE() win32_get_tmpfile_template()
+
+#define GETENV_HOME()  (getenv("HOME")  ? getenv("HOME")  : getenv("USERPROFILE"))
+#define GETENV_SHELL() (getenv("SHELL") ? getenv("SHELL") : (win32_setenv_shell(), getenv("SHELL")))
+
+#define TMUX_CONF_SEARCH_PATH() win32_get_conf_search_path()
+
+#endif
+
 #endif /* COMPAT_H */
diff --git a/configure.ac b/configure.ac
index 98b67a4d..6f04718d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,12 +3,13 @@
 AC_INIT([tmux], next-3.6)
 AC_PREREQ([2.60])
 
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
 AC_CONFIG_AUX_DIR(etc)
 AC_CONFIG_LIBOBJ_DIR(compat)
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 
-AC_CANONICAL_HOST
-
 # When CFLAGS isn't set at this stage and gcc is detected by the macro below,
 # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an
 # empty default.
@@ -41,10 +42,136 @@ if test "x$enable_fuzzing" = xyes; then
 		AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address"
 fi
 
+AC_ARG_ENABLE(
+	utf8proc,
+	AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed)
+)
+
+# Figure out the platform.
+AC_MSG_CHECKING(platform)
+case "$target_os" in
+	*aix*)
+		AC_MSG_RESULT(aix)
+		PLATFORM=aix
+		;;
+	*darwin*)
+		AC_MSG_RESULT(darwin)
+		PLATFORM=darwin
+		#
+		# macOS uses __dead2 instead of __dead, like FreeBSD. But it defines
+		# __dead away so it needs to be removed before we can replace it.
+		#
+		AC_DEFINE(BROKEN___DEAD)
+		#
+		# macOS CMSG_FIRSTHDR is broken, so redefine it with a working one.
+		# daemon works but has some stupid side effects, so use our internal
+		# version which has a workaround.
+		#
+		AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
+		AC_LIBOBJ(daemon)
+		AC_LIBOBJ(daemon-darwin)
+		#
+		# macOS wcwidth(3) is bad, so complain and suggest using utf8proc
+		# instead.
+		#
+		if test "x$enable_utf8proc" = x; then
+			AC_MSG_NOTICE([])
+			AC_MSG_NOTICE([	   macOS library support for Unicode is very poor,])
+			AC_MSG_NOTICE([	   particularly for complex codepoints like emojis;])
+			AC_MSG_NOTICE([	   to use these correctly, configuring with])
+			AC_MSG_NOTICE([	   --enable-utf8proc is recommended. To build])
+			AC_MSG_NOTICE([	   without anyway, use --disable-utf8proc])
+			AC_MSG_NOTICE([])
+			AC_MSG_ERROR([must give --enable-utf8proc or --disable-utf8proc])
+		fi
+		;;
+	*dragonfly*)
+		AC_MSG_RESULT(dragonfly)
+		PLATFORM=dragonfly
+		;;
+	*linux*)
+		AC_MSG_RESULT(linux)
+		PLATFORM=linux
+		;;
+	*freebsd*)
+		AC_MSG_RESULT(freebsd)
+		PLATFORM=freebsd
+		;;
+	*netbsd*)
+		AC_MSG_RESULT(netbsd)
+		PLATFORM=netbsd
+		;;
+	*openbsd*)
+		AC_MSG_RESULT(openbsd)
+		PLATFORM=openbsd
+		;;
+	*sunos*)
+		AC_MSG_RESULT(sunos)
+		PLATFORM=sunos
+		;;
+	*solaris*)
+		AC_MSG_RESULT(sunos)
+		PLATFORM=sunos
+		case `/usr/bin/nroff --version 2>&1` in
+			*GNU*)
+				# Solaris 11.4 and later use GNU groff.
+				MANFORMAT=mdoc
+				;;
+			*)
+				if test `uname -o 2>/dev/null` = illumos; then
+					# Illumos uses mandoc.
+					MANFORMAT=mdoc
+				else
+					# Solaris 2.0 to 11.3 use AT&T nroff.
+					MANFORMAT=man
+				fi
+				;;
+		esac
+		;;
+	*hpux*)
+		AC_MSG_RESULT(hpux)
+		PLATFORM=hpux
+		;;
+	*cygwin*|*msys*)
+		AC_MSG_RESULT(cygwin)
+		PLATFORM=cygwin
+		TARGET_WIN32=yes
+		AC_DEFINE(TARGET_WIN32)
+		AM_CONDITIONAL(TARGET_WIN32, test "x$TARGET_WIN32" = xyes)
+		;;
+	*haiku*)
+		AC_MSG_RESULT(haiku)
+		PLATFORM=haiku
+		;;
+	*)
+		AC_MSG_RESULT(unknown)
+		PLATFORM=unknown
+		;;
+esac
+AC_SUBST(PLATFORM)
+AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix)
+AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin)
+AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly)
+AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux)
+AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd)
+AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
+AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
+AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
+AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
+AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin)
+AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
+AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
+
+
 # Set up the compiler in two different ways and say yes we may want to install.
-AC_PROG_CC
-AM_PROG_CC_C_O
 m4_version_prereq(2.70, [AC_PROG_CC], [AC_PROG_CC_C99])
+
+if test "x$TARGET_WIN32" = xyes; then
+	AC_PROG_CXX
+	CFLAGS="$CFLAGS -isystem $(dirname $(readlink -f $0))/third_party/mingw_headers"
+	CXXFLAGS="$CXXFLAGS -std=c++17 -isystem $(dirname $(readlink -f $0))/third_party/mingw_headers -O2 -fpermissive -Wno-write-strings -Wno-class-conversion"
+fi
+
 AC_PROG_CPP
 AC_PROG_EGREP
 AC_PROG_INSTALL
@@ -381,10 +508,6 @@ if test "x$enable_utempter" = xyes; then
 fi
 
 # Look for utf8proc.
-AC_ARG_ENABLE(
-	utf8proc,
-	AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed)
-)
 if test "x$enable_utf8proc" = xyes; then
 	PKG_CHECK_MODULES(
 		LIBUTF8PROC,
@@ -874,118 +997,6 @@ AC_SUBST(DEFAULT_TERM)
 MANFORMAT=mdoc
 AC_SUBST(MANFORMAT)
 
-# Figure out the platform.
-AC_MSG_CHECKING(platform)
-case "$host_os" in
-	*aix*)
-		AC_MSG_RESULT(aix)
-		PLATFORM=aix
-		;;
-	*darwin*)
-		AC_MSG_RESULT(darwin)
-		PLATFORM=darwin
-		#
-		# macOS uses __dead2 instead of __dead, like FreeBSD. But it defines
-		# __dead away so it needs to be removed before we can replace it.
-		#
-		AC_DEFINE(BROKEN___DEAD)
-		#
-		# macOS CMSG_FIRSTHDR is broken, so redefine it with a working one.
-		# daemon works but has some stupid side effects, so use our internal
-		# version which has a workaround.
-		#
-		AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
-		AC_LIBOBJ(daemon)
-		AC_LIBOBJ(daemon-darwin)
-		#
-		# macOS wcwidth(3) is bad, so complain and suggest using utf8proc
-		# instead.
-		#
-		if test "x$enable_utf8proc" = x; then
-			AC_MSG_NOTICE([])
-			AC_MSG_NOTICE([	   macOS library support for Unicode is very poor,])
-			AC_MSG_NOTICE([	   particularly for complex codepoints like emojis;])
-			AC_MSG_NOTICE([	   to use these correctly, configuring with])
-			AC_MSG_NOTICE([	   --enable-utf8proc is recommended. To build])
-			AC_MSG_NOTICE([	   without anyway, use --disable-utf8proc])
-			AC_MSG_NOTICE([])
-			AC_MSG_ERROR([must give --enable-utf8proc or --disable-utf8proc])
-		fi
-		;;
-	*dragonfly*)
-		AC_MSG_RESULT(dragonfly)
-		PLATFORM=dragonfly
-		;;
-	*linux*)
-		AC_MSG_RESULT(linux)
-		PLATFORM=linux
-		;;
-	*freebsd*)
-		AC_MSG_RESULT(freebsd)
-		PLATFORM=freebsd
-		;;
-	*netbsd*)
-		AC_MSG_RESULT(netbsd)
-		PLATFORM=netbsd
-		;;
-	*openbsd*)
-		AC_MSG_RESULT(openbsd)
-		PLATFORM=openbsd
-		;;
-	*sunos*)
-		AC_MSG_RESULT(sunos)
-		PLATFORM=sunos
-		;;
-	*solaris*)
-		AC_MSG_RESULT(sunos)
-		PLATFORM=sunos
-		case `/usr/bin/nroff --version 2>&1` in
-			*GNU*)
-				# Solaris 11.4 and later use GNU groff.
-				MANFORMAT=mdoc
-				;;
-			*)
-				if test `uname -o 2>/dev/null` = illumos; then
-					# Illumos uses mandoc.
-					MANFORMAT=mdoc
-				else
-					# Solaris 2.0 to 11.3 use AT&T nroff.
-					MANFORMAT=man
-				fi
-				;;
-		esac
-		;;
-	*hpux*)
-		AC_MSG_RESULT(hpux)
-		PLATFORM=hpux
-		;;
-	*cygwin*|*msys*)
-		AC_MSG_RESULT(cygwin)
-		PLATFORM=cygwin
-		;;
-	*haiku*)
-		AC_MSG_RESULT(haiku)
-		PLATFORM=haiku
-		;;
-	*)
-		AC_MSG_RESULT(unknown)
-		PLATFORM=unknown
-		;;
-esac
-AC_SUBST(PLATFORM)
-AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix)
-AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin)
-AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly)
-AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux)
-AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd)
-AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
-AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
-AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
-AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
-AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin)
-AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
-AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
-
 # Set the default lock command
 DEFAULT_LOCK_CMD="lock -np"
 AC_MSG_CHECKING(lock-command)
diff --git a/osdep-win32-cpp.cpp b/osdep-win32-cpp.cpp
new file mode 100644
index 00000000..fb9c26ec
--- /dev/null
+++ b/osdep-win32-cpp.cpp
@@ -0,0 +1,87 @@
+#include <cwchar>
+
+#define WIN32_LEAN_AND_MEAN
+#define _WIN32_DCOM
+
+#define sprintf_s sprintf
+
+#include <windows.h>
+#include <comutil.h>
+#include <stringapiset.h>
+#include <tlhelp32.h>
+#include <wbemidl.h>
+
+void
+win32_setenv_shell_impl(void);
+
+void
+win32_setenv_shell_impl(void)
+{
+	unsigned pid = GetCurrentProcessId();
+	int ppid = -1;
+	HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+	PROCESSENTRY32 pe = { 0 };
+	IWbemLocator* wbem_locator       = nullptr;
+	IWbemServices* wbem_services     = nullptr;
+	IEnumWbemClassObject* enum_wbem  = nullptr;
+
+	pe.dwSize = sizeof(PROCESSENTRY32);
+
+	if (Process32First(h, &pe)) {
+		do {
+			if (pe.th32ProcessID == pid)
+				ppid = pe.th32ParentProcessID;
+		} while (Process32Next(h, &pe));
+	}
+
+	CloseHandle(h);
+
+	CoInitializeEx(0, COINIT_MULTITHREADED);
+	CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr);
+	CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbem_locator);
+
+	wbem_locator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbem_services);
+	wchar_t* query = new wchar_t[4096];
+	swprintf(query, 4096, L"select commandline from win32_process where processid = %d", ppid);
+	wbem_services->ExecQuery(L"WQL", query, WBEM_FLAG_FORWARD_ONLY, nullptr, &enum_wbem);
+	delete[] query;
+
+	if (enum_wbem) {
+		IWbemClassObject *result = nullptr;
+		ULONG returned_count = 0;
+
+		if(enum_wbem->Next(WBEM_INFINITE, 1, &result, &returned_count) == S_OK) {
+			VARIANT process_id;
+			VARIANT command_line;
+
+			result->Get(L"CommandLine", 0, &command_line, 0, 0);
+
+			wchar_t* command_line_utf16 = command_line.bstrVal;
+			size_t size = WideCharToMultiByte(CP_UTF8, 0, command_line_utf16, -1, nullptr, 0, nullptr, nullptr) + 1;
+			char* command_line_utf8 = new char[size];
+
+			WideCharToMultiByte(CP_UTF8, 0, command_line_utf16, -1, command_line_utf8, size, nullptr, nullptr);
+
+			SysFreeString(command_line_utf16);
+
+			setenv("SHELL", command_line_utf8, 1);
+
+			delete[] command_line_utf8;
+
+			result->Release();
+		}
+	}
+}
+
+extern "C" {
+
+void
+win32_setenv_shell(void);
+
+void
+win32_setenv_shell(void)
+{
+	win32_setenv_shell_impl();
+}
+
+}
diff --git a/osdep-win32.c b/osdep-win32.c
new file mode 100644
index 00000000..e8ea6316
--- /dev/null
+++ b/osdep-win32.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tmux.h"
+#include "xmalloc.h"
+
+static int in_cygwin_virtual_filesystem(void);
+
+#define PROFILE_TMPDIR "/AppData/Local/Temp/"
+
+static char	tmpdir[4096]           = {0};
+static char	socket_dir[4096]       = {0};
+static char	tmpfile_template[4096] = {0};
+static int	in_cygwin_fs	       = -1;
+
+static int
+in_cygwin_virtual_filesystem(void)
+{
+	if (in_cygwin_fs != -1)
+		return in_cygwin_fs;
+
+	in_cygwin_fs = 0;
+
+	if (
+		(access("/bin/sh",     F_OK) == 0) &&
+		(access("/usr",        F_OK) == 0) &&
+		(access("/home",       F_OK) == 0) &&
+		(access("/proc",       F_OK) == 0) &&
+		(access("/var",        F_OK) == 0) &&
+		(access("/tmp",        F_OK) == 0) &&
+		(access("/dev/null",   F_OK) == 0) &&
+		(access("/dev/random", F_OK) == 0) &&
+		(access("/dev/stdout", F_OK) == 0) &&
+		(access("/proc/stat",  F_OK) == 0)
+	) {
+		in_cygwin_fs = 1;
+	}
+
+	return in_cygwin_fs;
+}
+
+const char *
+win32_get_tmpdir(void)
+{
+	char	*profile_dir = NULL;
+
+	if (*tmpdir)
+		return tmpdir;
+
+	if (in_cygwin_virtual_filesystem()) {
+		strncpy(tmpdir, "/tmp/", 4096);
+		return tmpdir;
+	}
+
+	if ((profile_dir = getenv("USERPROFILE")))
+		snprintf(tmpdir, 4096, "%s%s", profile_dir, PROFILE_TMPDIR);
+
+	return tmpdir;
+}
+
+const char *
+win32_get_socket_dir_search_path(void)
+{
+	if (*socket_dir)
+		return socket_dir;
+
+	snprintf(socket_dir, 4096, "$TMUX_TMPDIR:%s", win32_get_tmpdir());
+
+	return socket_dir;
+}
+
+const char *
+win32_get_conf_search_path(void)
+{
+	if (in_cygwin_virtual_filesystem())
+		return TMUX_CONF;
+
+	return TMUX_CONF_WIN32;
+}
+
+const char *
+win32_get_tmpfile_template(void)
+{
+	if (*tmpfile_template)
+		return tmpfile_template;
+
+	snprintf(tmpfile_template, 4096, "%s/tmux.XXXXXXXX", win32_get_tmpdir());
+
+	return tmpfile_template;
+}
+
+const char *
+win32_get_shell_cmd_switch(const char *shell)
+{
+	if (strstr(shell, "cmd.exe") != NULL)
+		return "/c";
+	else
+		return "-c";
+}
diff --git a/popup.c b/popup.c
index 4cd147e1..7c895170 100644
--- a/popup.c
+++ b/popup.c
@@ -778,7 +778,7 @@ popup_editor(struct client *c, const char *buf, size_t len,
 	int			 fd;
 	FILE			*f;
 	char			*cmd;
-	char			 path[] = _PATH_TMP "tmux.XXXXXXXX";
+	char			*path = (char *)TMPFILE_TEMPLATE();
 	const char		*editor;
 	u_int			 px, py, sx, sy;
 
@@ -810,7 +810,7 @@ popup_editor(struct client *c, const char *buf, size_t len,
 
 	xasprintf(&cmd, "%s %s", editor, path);
 	if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT,
-	    NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL,
+	    NULL, px, py, sx, sy, NULL, cmd, 0, NULL, TMPDIR(), NULL, c, NULL,
 	    NULL, NULL, popup_editor_close_cb, pe) != 0) {
 		popup_editor_free(pe);
 		free(cmd);
diff --git a/spawn.c b/spawn.c
index d321dba4..559a7f4f 100644
--- a/spawn.c
+++ b/spawn.c
@@ -456,7 +456,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
 			xasprintf(&argv0, "%s", cp + 1);
 		else
 			xasprintf(&argv0, "%s", new_wp->shell);
-		execl(new_wp->shell, argv0, "-c", tmp, (char *)NULL);
+		execl(new_wp->shell, argv0, SHELL_CMD_SWITCH(new_wp->shell), tmp, (char *)NULL);
 		_exit(1);
 	}
 	if (cp != NULL && cp[1] != '\0')
diff --git a/third_party/mingw_headers/comutil.h b/third_party/mingw_headers/comutil.h
new file mode 100644
index 00000000..ddb09063
--- /dev/null
+++ b/third_party/mingw_headers/comutil.h
@@ -0,0 +1,1233 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#ifndef _INC_COMUTIL
+#define _INC_COMUTIL
+
+#include <ole2.h>
+#include <stdio.h>
+
+#ifndef _COM_ASSERT
+#define _COM_ASSERT(x) ((void)0)
+#endif
+
+#define _COM_MEMCPY_S(dest,destsize,src,count) memcpy(dest,src,count)
+
+/* Use of wsprintf might be impossible, if strsafe.h is included. */
+#ifndef __STDC_SECURE_LIB__
+#define _COM_PRINTF_S_1(dest,destsize,format,arg1) wsprintf(dest,format,arg1)
+#elif defined(UNICODE)
+#define _COM_PRINTF_S_1(dest,destsize,format,arg1) swprintf_s(dest,destsize,format,arg1)
+#else
+#define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1)
+#endif
+
+#ifdef __cplusplus
+
+#pragma push_macro("new")
+#undef new
+
+#ifndef WINAPI
+#if defined(_ARM_)
+#define WINAPI
+#else
+#define WINAPI __stdcall
+#endif
+#endif
+
+class _com_error;
+
+void WINAPI _com_issue_error(HRESULT);
+
+class _bstr_t;
+class _variant_t;
+
+namespace _com_util {
+  inline void CheckError(HRESULT hr) {
+    if(FAILED(hr)) { _com_issue_error(hr); }
+  }
+}
+
+namespace _com_util {
+  BSTR WINAPI ConvertStringToBSTR(const char *pSrc);
+  char *WINAPI ConvertBSTRToString(BSTR pSrc);
+}
+
+class _bstr_t {
+public:
+  _bstr_t() throw();
+  _bstr_t(const _bstr_t &s) throw();
+  _bstr_t(const char *s);
+  _bstr_t(const wchar_t *s);
+  _bstr_t(const _variant_t &var);
+  _bstr_t(BSTR bstr,bool fCopy);
+  ~_bstr_t() throw();
+  _bstr_t &operator=(const _bstr_t &s) throw();
+  _bstr_t &operator=(const char *s);
+  _bstr_t &operator=(const wchar_t *s);
+  _bstr_t &operator=(const _variant_t &var);
+  _bstr_t &operator+=(const _bstr_t &s);
+  _bstr_t operator+(const _bstr_t &s) const;
+  friend _bstr_t operator+(const char *s1,const _bstr_t &s2);
+  friend _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2);
+  operator const wchar_t *() const throw();
+  operator wchar_t *() const throw();
+  operator const char *() const;
+  operator char *() const;
+  bool operator!() const throw();
+  bool operator==(const _bstr_t &str) const throw();
+  bool operator!=(const _bstr_t &str) const throw();
+  bool operator<(const _bstr_t &str) const throw();
+  bool operator>(const _bstr_t &str) const throw();
+  bool operator<=(const _bstr_t &str) const throw();
+  bool operator>=(const _bstr_t &str) const throw();
+  BSTR copy(bool fCopy = true) const;
+  unsigned int length() const throw();
+  void Assign(BSTR s);
+  BSTR &GetBSTR();
+  BSTR *GetAddress();
+  void Attach(BSTR s);
+  BSTR Detach() throw();
+private:
+  class Data_t {
+  public:
+    Data_t(const char *s);
+    Data_t(const wchar_t *s);
+    Data_t(BSTR bstr,bool fCopy);
+    Data_t(const _bstr_t &s1,const _bstr_t &s2);
+    unsigned __LONG32 AddRef() throw();
+    unsigned __LONG32 Release() throw();
+    unsigned __LONG32 RefCount() const throw();
+    operator const wchar_t *() const throw();
+    operator const char *() const;
+    const wchar_t *GetWString() const throw();
+    wchar_t *&GetWString() throw();
+    const char *GetString() const;
+    BSTR Copy() const;
+    void Assign(BSTR s);
+    void Attach(BSTR s) throw();
+    unsigned int Length() const throw();
+    int Compare(const Data_t &str) const throw();
+    void *operator new(size_t sz);
+  private:
+    BSTR m_wstr;
+    mutable char *m_str;
+    unsigned __LONG32 m_RefCount;
+    Data_t() throw();
+    Data_t(const Data_t &s) throw();
+    ~Data_t() throw();
+    void _Free() throw();
+  };
+private:
+  Data_t *m_Data;
+private:
+  void _AddRef() throw();
+  void _Free() throw();
+  int _Compare(const _bstr_t &str) const throw();
+};
+
+inline _bstr_t::_bstr_t() throw() : m_Data(NULL) { }
+
+inline _bstr_t::_bstr_t(const _bstr_t &s) throw() : m_Data(s.m_Data) { _AddRef(); }
+
+inline _bstr_t::_bstr_t(const char *s) : m_Data(new Data_t(s)) {
+  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+}
+
+inline _bstr_t::_bstr_t(const wchar_t *s) : m_Data(new Data_t(s)) {
+  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+}
+
+inline _bstr_t::_bstr_t(BSTR bstr,bool fCopy) : m_Data(new Data_t(bstr,fCopy)) {
+  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+}
+
+inline _bstr_t::~_bstr_t() throw() { _Free(); }
+
+inline _bstr_t &_bstr_t::operator=(const _bstr_t &s) throw() {
+  if(this!=&s) {
+    _Free();
+    m_Data = s.m_Data;
+    _AddRef();
+  }
+  return *this;
+}
+
+inline _bstr_t &_bstr_t::operator=(const char *s) {
+  _COM_ASSERT(!s || static_cast<const char *>(*this)!=s);
+  if(!s || static_cast<const char *>(*this)!=s) {
+    _Free();
+    m_Data = new Data_t(s);
+    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+  }
+  return *this;
+}
+
+inline _bstr_t &_bstr_t::operator=(const wchar_t *s) {
+  _COM_ASSERT(!s || static_cast<const wchar_t *>(*this)!=s);
+  if(!s || static_cast<const wchar_t *>(*this)!=s) {
+    _Free();
+    m_Data = new Data_t(s);
+    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+  }
+  return *this;
+}
+
+inline _bstr_t &_bstr_t::operator+=(const _bstr_t &s) {
+  Data_t *newData = new Data_t(*this,s);
+  if(!newData) { _com_issue_error(E_OUTOFMEMORY); }
+  else {
+    _Free();
+    m_Data = newData;
+  }
+  return *this;
+}
+
+inline _bstr_t _bstr_t::operator+(const _bstr_t &s) const {
+  _bstr_t b = *this;
+  b += s;
+  return b;
+}
+
+inline _bstr_t operator+(const char *s1,const _bstr_t &s2) {
+  _bstr_t b = s1;
+  b += s2;
+  return b;
+}
+
+inline _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2) {
+  _bstr_t b = s1;
+  b += s2;
+  return b;
+}
+
+inline _bstr_t::operator const wchar_t *() const throw() { return (m_Data!=NULL) ? m_Data->GetWString() : NULL; }
+inline _bstr_t::operator wchar_t *() const throw() { return const_cast<wchar_t *>((m_Data!=NULL) ? m_Data->GetWString() : NULL); }
+inline _bstr_t::operator const char *() const { return (m_Data!=NULL) ? m_Data->GetString() : NULL; }
+inline _bstr_t::operator char *() const { return const_cast<char *>((m_Data!=NULL) ? m_Data->GetString() : NULL); }
+inline bool _bstr_t::operator!() const throw() { return (m_Data!=NULL) ? !m_Data->GetWString() : true; }
+inline bool _bstr_t::operator==(const _bstr_t &str) const throw() { return _Compare(str)==0; }
+inline bool _bstr_t::operator!=(const _bstr_t &str) const throw() { return _Compare(str)!=0; }
+inline bool _bstr_t::operator<(const _bstr_t &str) const throw() { return _Compare(str)<0; }
+inline bool _bstr_t::operator>(const _bstr_t &str) const throw() { return _Compare(str)>0; }
+inline bool _bstr_t::operator<=(const _bstr_t &str) const throw() { return _Compare(str)<=0; }
+inline bool _bstr_t::operator>=(const _bstr_t &str) const throw() { return _Compare(str)>=0; }
+inline BSTR _bstr_t::copy(bool fCopy) const { return (m_Data!=NULL) ? (fCopy ? m_Data->Copy() : m_Data->GetWString()) : NULL; }
+inline unsigned int _bstr_t::length() const throw() { return (m_Data!=NULL) ? m_Data->Length() : 0; }
+inline void _bstr_t::Assign(BSTR s) {
+  _COM_ASSERT(!s || !m_Data || m_Data->GetWString()!=s);
+  if(!s || !m_Data || m_Data->GetWString()!=s) {
+    _Free();
+    m_Data = new Data_t(s,TRUE);
+    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+  }
+}
+
+inline BSTR &_bstr_t::GetBSTR() {
+  if(!m_Data) {
+    m_Data = new Data_t(0,FALSE);
+    if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+  }
+  return m_Data->GetWString();
+}
+
+inline BSTR *_bstr_t::GetAddress() {
+  Attach(0);
+  return &m_Data->GetWString();
+}
+
+inline void _bstr_t::Attach(BSTR s) {
+  _Free();
+  m_Data = new Data_t(s,FALSE);
+  if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); }
+}
+
+inline BSTR _bstr_t::Detach() throw () {
+  _COM_ASSERT(m_Data!=NULL && m_Data->RefCount()==1);
+  if(m_Data!=NULL && m_Data->RefCount()==1) {
+    BSTR b = m_Data->GetWString();
+    m_Data->GetWString() = NULL;
+    _Free();
+    return b;
+  } else {
+    _com_issue_error(E_POINTER);
+    return NULL;
+  }
+}
+
+inline void _bstr_t::_AddRef() throw() {
+  if(m_Data!=NULL) m_Data->AddRef();
+}
+
+inline void _bstr_t::_Free() throw() {
+  if(m_Data!=NULL) {
+    m_Data->Release();
+    m_Data = NULL;
+  }
+}
+
+inline int _bstr_t::_Compare(const _bstr_t &str) const throw() {
+  if(m_Data==str.m_Data) return 0;
+  if(!m_Data) return -1;
+  if(!str.m_Data) return 1;
+  return m_Data->Compare(*str.m_Data);
+}
+
+inline _bstr_t::Data_t::Data_t(const char *s) : m_str(NULL),m_RefCount(1) {
+  m_wstr = _com_util::ConvertStringToBSTR(s);
+}
+
+inline _bstr_t::Data_t::Data_t(const wchar_t *s) : m_str(NULL),m_RefCount(1) {
+  m_wstr = ::SysAllocString(s);
+  if(!m_wstr && s!=NULL) { _com_issue_error(E_OUTOFMEMORY); }
+}
+
+inline _bstr_t::Data_t::Data_t(BSTR bstr,bool fCopy) : m_str(NULL),m_RefCount(1) {
+  if(fCopy && bstr!=NULL) {
+    m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));
+    if(!m_wstr) { _com_issue_error(E_OUTOFMEMORY); }
+  } else m_wstr = bstr;
+}
+
+inline _bstr_t::Data_t::Data_t(const _bstr_t &s1,const _bstr_t &s2) : m_str(NULL),m_RefCount(1) {
+  const unsigned int l1 = s1.length();
+  const unsigned int l2 = s2.length();
+  m_wstr = ::SysAllocStringByteLen(NULL,(l1 + l2) *sizeof(wchar_t));
+  if(!m_wstr) {
+    _com_issue_error(E_OUTOFMEMORY);
+    return;
+  }
+  const wchar_t *wstr1 = static_cast<const wchar_t *>(s1);
+  if(wstr1!=NULL) {
+    _COM_MEMCPY_S(m_wstr,(l1 + l2 + 1) *sizeof(wchar_t),wstr1,(l1 + 1) *sizeof(wchar_t));
+  }
+  const wchar_t *wstr2 = static_cast<const wchar_t *>(s2);
+  if(wstr2!=NULL) {
+    _COM_MEMCPY_S(m_wstr + l1,(l2 + 1) *sizeof(wchar_t),wstr2,(l2 + 1) *sizeof(wchar_t));
+  }
+}
+
+inline unsigned __LONG32 _bstr_t::Data_t::AddRef() throw() {
+  InterlockedIncrement(reinterpret_cast<LONG*>(&m_RefCount));
+  return m_RefCount;
+}
+
+inline unsigned __LONG32 _bstr_t::Data_t::Release() throw() {
+  unsigned __LONG32 cRef = InterlockedDecrement(reinterpret_cast<LONG*>(&m_RefCount));
+  if(cRef==0) delete this;
+  return cRef;
+}
+
+inline unsigned __LONG32 _bstr_t::Data_t::RefCount() const throw() { return m_RefCount; }
+inline _bstr_t::Data_t::operator const wchar_t *() const throw() { return m_wstr; }
+inline _bstr_t::Data_t::operator const char *() const { return GetString(); }
+inline const wchar_t *_bstr_t::Data_t::GetWString() const throw() { return m_wstr; }
+inline wchar_t *&_bstr_t::Data_t::GetWString() throw() { return m_wstr; }
+inline const char *_bstr_t::Data_t::GetString() const {
+  if(!m_str) m_str = _com_util::ConvertBSTRToString(m_wstr);
+  return m_str;
+}
+inline BSTR _bstr_t::Data_t::Copy() const {
+  if(m_wstr!=NULL) {
+    BSTR bstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(m_wstr),::SysStringByteLen(m_wstr));
+    if(!bstr) { _com_issue_error(E_OUTOFMEMORY); }
+    return bstr;
+  }
+  return NULL;
+}
+inline void _bstr_t::Data_t::Assign(BSTR s) {
+  _Free();
+  if(s!=NULL) {
+    m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(s),::SysStringByteLen(s));
+    m_str = 0;
+  }
+}
+inline void _bstr_t::Data_t::Attach(BSTR s) throw() {
+  _Free();
+  m_wstr = s;
+  m_str = 0;
+  m_RefCount = 1;
+}
+inline unsigned int _bstr_t::Data_t::Length() const throw() { return m_wstr ? ::SysStringLen(m_wstr) : 0; }
+inline int _bstr_t::Data_t::Compare(const _bstr_t::Data_t &str) const throw() {
+  if(!m_wstr) return str.m_wstr ? -1 : 0;
+  if(!str.m_wstr) return 1;
+  const unsigned int l1 = ::SysStringLen(m_wstr);
+  const unsigned int l2 = ::SysStringLen(str.m_wstr);
+  unsigned int len = l1;
+  if(len>l2) len = l2;
+  BSTR bstr1 = m_wstr;
+  BSTR bstr2 = str.m_wstr;
+  while (len-->0) {
+    if(*bstr1++!=*bstr2++) return bstr1[-1] - bstr2[-1];
+  }
+  return (l1<l2) ? -1 : (l1==l2) ? 0 : 1;
+}
+
+#ifdef _COM_OPERATOR_NEW_THROWS
+inline void *_bstr_t::Data_t::operator new(size_t sz) {
+  try {
+    return ::operator new(sz);
+  } catch (...) {
+    return NULL;
+  }
+}
+#else
+inline void *_bstr_t::Data_t::operator new(size_t sz) {
+  return ::operator new(sz);
+}
+#endif
+
+inline _bstr_t::Data_t::~Data_t() throw() { _Free(); }
+inline void _bstr_t::Data_t::_Free() throw() {
+  if(m_wstr!=NULL) ::SysFreeString(m_wstr);
+  if(m_str!=NULL) delete [] m_str;
+}
+
+class _variant_t : public ::tagVARIANT {
+public:
+  _variant_t() throw();
+  _variant_t(const VARIANT &varSrc);
+  _variant_t(const VARIANT *pSrc);
+  _variant_t(const _variant_t &varSrc);
+  _variant_t(VARIANT &varSrc,bool fCopy);
+  _variant_t(short sSrc,VARTYPE vtSrc = VT_I2);
+  _variant_t(__LONG32 lSrc,VARTYPE vtSrc = VT_I4);
+  _variant_t(float fltSrc) throw();
+  _variant_t(double dblSrc,VARTYPE vtSrc = VT_R8);
+  _variant_t(const CY &cySrc) throw();
+  _variant_t(const _bstr_t &bstrSrc);
+  _variant_t(const wchar_t *pSrc);
+  _variant_t(const char *pSrc);
+  _variant_t(IDispatch *pSrc,bool fAddRef = true) throw();
+  _variant_t(bool boolSrc) throw();
+  _variant_t(IUnknown *pSrc,bool fAddRef = true) throw();
+  _variant_t(const DECIMAL &decSrc) throw();
+  _variant_t(BYTE bSrc) throw();
+  _variant_t(char cSrc) throw();
+  _variant_t(unsigned short usSrc) throw();
+  _variant_t(unsigned __LONG32 ulSrc) throw();
+#ifndef __CYGWIN__
+  _variant_t(int iSrc) throw();
+  _variant_t(unsigned int uiSrc) throw();
+#endif
+  __MINGW_EXTENSION _variant_t(__int64 i8Src) throw();
+  __MINGW_EXTENSION _variant_t(unsigned __int64 ui8Src) throw();
+  ~_variant_t() throw();
+  operator short() const;
+  operator __LONG32() const;
+  operator float() const;
+  operator double() const;
+  operator CY() const;
+  operator _bstr_t() const;
+  operator IDispatch*() const;
+  operator bool() const;
+  operator IUnknown*() const;
+  operator DECIMAL() const;
+  operator BYTE() const;
+  operator VARIANT() const throw();
+  operator char() const;
+  operator unsigned short() const;
+  operator unsigned __LONG32() const;
+#ifndef __CYGWIN__
+  operator int() const;
+  operator unsigned int() const;
+#endif
+  __MINGW_EXTENSION operator __int64() const;
+  __MINGW_EXTENSION operator unsigned __int64() const;
+  _variant_t &operator=(const VARIANT &varSrc);
+  _variant_t &operator=(const VARIANT *pSrc);
+  _variant_t &operator=(const _variant_t &varSrc);
+  _variant_t &operator=(short sSrc);
+  _variant_t &operator=(__LONG32 lSrc);
+  _variant_t &operator=(float fltSrc);
+  _variant_t &operator=(double dblSrc);
+  _variant_t &operator=(const CY &cySrc);
+  _variant_t &operator=(const _bstr_t &bstrSrc);
+  _variant_t &operator=(const wchar_t *pSrc);
+  _variant_t &operator=(const char *pSrc);
+  _variant_t &operator=(IDispatch *pSrc);
+  _variant_t &operator=(bool boolSrc);
+  _variant_t &operator=(IUnknown *pSrc);
+  _variant_t &operator=(const DECIMAL &decSrc);
+  _variant_t &operator=(BYTE bSrc);
+  _variant_t &operator=(char cSrc);
+  _variant_t &operator=(unsigned short usSrc);
+  _variant_t &operator=(unsigned __LONG32 ulSrc);
+#ifndef __CYGWIN__
+  _variant_t &operator=(int iSrc);
+  _variant_t &operator=(unsigned int uiSrc);
+#endif
+  __MINGW_EXTENSION _variant_t &operator=(__int64 i8Src);
+  __MINGW_EXTENSION _variant_t &operator=(unsigned __int64 ui8Src);
+  bool operator==(const VARIANT &varSrc) const throw();
+  bool operator==(const VARIANT *pSrc) const throw();
+  bool operator!=(const VARIANT &varSrc) const throw();
+  bool operator!=(const VARIANT *pSrc) const throw();
+  void Clear();
+  void Attach(VARIANT &varSrc);
+  VARIANT Detach();
+  VARIANT &GetVARIANT() throw();
+  VARIANT *GetAddress();
+  void ChangeType(VARTYPE vartype,const _variant_t *pSrc = NULL);
+  void SetString(const char *pSrc);
+};
+
+inline _variant_t::_variant_t() throw() { ::VariantInit(this); }
+inline _variant_t::_variant_t(const VARIANT &varSrc) {
+  ::VariantInit(this);
+  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc)));
+}
+inline _variant_t::_variant_t(const VARIANT *pSrc) {
+  if(!pSrc) { _com_issue_error(E_POINTER); }
+  else {
+    ::VariantInit(this);
+    _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc)));
+  }
+}
+inline _variant_t::_variant_t(const _variant_t &varSrc) {
+  ::VariantInit(this);
+  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc))));
+}
+inline _variant_t::_variant_t(VARIANT &varSrc,bool fCopy) {
+  if(fCopy) {
+    ::VariantInit(this);
+    _com_util::CheckError(::VariantCopy(this,&varSrc));
+  } else {
+    _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
+    V_VT(&varSrc) = VT_EMPTY;
+  }
+}
+inline _variant_t::_variant_t(short sSrc,VARTYPE vtSrc) {
+  if((vtSrc!=VT_I2) && (vtSrc!=VT_BOOL)) {
+    _com_issue_error(E_INVALIDARG);
+    return;
+  }
+  if(vtSrc==VT_BOOL) {
+    V_VT(this) = VT_BOOL;
+    V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE);
+  } else {
+    V_VT(this) = VT_I2;
+    V_I2(this) = sSrc;
+  }
+}
+inline _variant_t::_variant_t(__LONG32 lSrc,VARTYPE vtSrc) {
+  if((vtSrc!=VT_I4) && (vtSrc!=VT_ERROR) && (vtSrc!=VT_BOOL)) {
+    _com_issue_error(E_INVALIDARG);
+    return;
+  }
+  if(vtSrc==VT_ERROR) {
+    V_VT(this) = VT_ERROR;
+    V_ERROR(this) = lSrc;
+  } else if(vtSrc==VT_BOOL) {
+    V_VT(this) = VT_BOOL;
+    V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE);
+  } else {
+    V_VT(this) = VT_I4;
+    V_I4(this) = lSrc;
+  }
+}
+inline _variant_t::_variant_t(float fltSrc) throw() {
+  V_VT(this) = VT_R4;
+  V_R4(this) = fltSrc;
+}
+
+inline _variant_t::_variant_t(double dblSrc,VARTYPE vtSrc) {
+  if((vtSrc!=VT_R8) && (vtSrc!=VT_DATE)) {
+    _com_issue_error(E_INVALIDARG);
+    return;
+  }
+  if(vtSrc==VT_DATE) {
+    V_VT(this) = VT_DATE;
+    V_DATE(this) = dblSrc;
+  } else {
+    V_VT(this) = VT_R8;
+    V_R8(this) = dblSrc;
+  }
+}
+inline _variant_t::_variant_t(const CY &cySrc) throw() {
+  V_VT(this) = VT_CY;
+  V_CY(this) = cySrc;
+}
+inline _variant_t::_variant_t(const _bstr_t &bstrSrc) {
+  V_VT(this) = VT_BSTR;
+  BSTR bstr = static_cast<wchar_t *>(bstrSrc);
+  if(!bstr) V_BSTR(this) = NULL;
+  else {
+    V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));
+    if(!(V_BSTR(this))) { _com_issue_error(E_OUTOFMEMORY); }
+  }
+}
+inline _variant_t::_variant_t(const wchar_t *pSrc) {
+  V_VT(this) = VT_BSTR;
+  V_BSTR(this) = ::SysAllocString(pSrc);
+  if(!(V_BSTR(this)) && pSrc!=NULL) { _com_issue_error(E_OUTOFMEMORY); }
+}
+inline _variant_t::_variant_t(const char *pSrc) {
+  V_VT(this) = VT_BSTR;
+  V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc);
+}
+inline _variant_t::_variant_t(IDispatch *pSrc,bool fAddRef) throw() {
+  V_VT(this) = VT_DISPATCH;
+  V_DISPATCH(this) = pSrc;
+  if(fAddRef && V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef();
+}
+inline _variant_t::_variant_t(bool boolSrc) throw() {
+  V_VT(this) = VT_BOOL;
+  V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE);
+}
+inline _variant_t::_variant_t(IUnknown *pSrc,bool fAddRef) throw() {
+  V_VT(this) = VT_UNKNOWN;
+  V_UNKNOWN(this) = pSrc;
+  if(fAddRef && V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef();
+}
+inline _variant_t::_variant_t(const DECIMAL &decSrc) throw() {
+  V_DECIMAL(this) = decSrc;
+  V_VT(this) = VT_DECIMAL;
+}
+inline _variant_t::_variant_t(BYTE bSrc) throw() {
+  V_VT(this) = VT_UI1;
+  V_UI1(this) = bSrc;
+}
+inline _variant_t::_variant_t(char cSrc) throw() {
+  V_VT(this) = VT_I1;
+  V_I1(this) = cSrc;
+}
+inline _variant_t::_variant_t(unsigned short usSrc) throw() {
+  V_VT(this) = VT_UI2;
+  V_UI2(this) = usSrc;
+}
+inline _variant_t::_variant_t(unsigned __LONG32 ulSrc) throw() {
+  V_VT(this) = VT_UI4;
+  V_UI4(this) = ulSrc;
+}
+#ifndef __CYGWIN__
+inline _variant_t::_variant_t(int iSrc) throw() {
+  V_VT(this) = VT_INT;
+  V_INT(this) = iSrc;
+}
+inline _variant_t::_variant_t(unsigned int uiSrc) throw() {
+  V_VT(this) = VT_UINT;
+  V_UINT(this) = uiSrc;
+}
+#endif
+__MINGW_EXTENSION inline _variant_t::_variant_t(__int64 i8Src) throw() {
+  V_VT(this) = VT_I8;
+  V_I8(this) = i8Src;
+}
+__MINGW_EXTENSION inline _variant_t::_variant_t(unsigned __int64 ui8Src) throw() {
+  V_VT(this) = VT_UI8;
+  V_UI8(this) = ui8Src;
+}
+inline _variant_t::operator short() const {
+  if(V_VT(this)==VT_I2) return V_I2(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_I2,this);
+  return V_I2(&varDest);
+}
+inline _variant_t::operator __LONG32() const {
+  if(V_VT(this)==VT_I4) return V_I4(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_I4,this);
+  return V_I4(&varDest);
+}
+
+inline _variant_t::operator float() const {
+  if(V_VT(this)==VT_R4) return V_R4(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_R4,this);
+  return V_R4(&varDest);
+}
+
+inline _variant_t::operator double() const {
+  if(V_VT(this)==VT_R8) return V_R8(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_R8,this);
+  return V_R8(&varDest);
+}
+
+inline _variant_t::operator CY() const {
+  if(V_VT(this)==VT_CY) return V_CY(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_CY,this);
+  return V_CY(&varDest);
+}
+
+inline _variant_t::operator _bstr_t() const {
+  if(V_VT(this)==VT_BSTR) return V_BSTR(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_BSTR,this);
+  return V_BSTR(&varDest);
+}
+
+inline _variant_t::operator IDispatch*() const {
+  if(V_VT(this)==VT_DISPATCH) {
+    if(V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef();
+    return V_DISPATCH(this);
+  }
+  _variant_t varDest;
+  varDest.ChangeType(VT_DISPATCH,this);
+  if(V_DISPATCH(&varDest)!=NULL) V_DISPATCH(&varDest)->AddRef();
+  return V_DISPATCH(&varDest);
+}
+inline _variant_t::operator bool() const {
+  if(V_VT(this)==VT_BOOL) return V_BOOL(this) ? true : false;
+  _variant_t varDest;
+  varDest.ChangeType(VT_BOOL,this);
+  return (V_BOOL(&varDest)==VARIANT_TRUE) ? true : false;
+}
+
+inline _variant_t::operator IUnknown*() const {
+  if(V_VT(this)==VT_UNKNOWN) {
+    if(V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef();
+    return V_UNKNOWN(this);
+  }
+  _variant_t varDest;
+  varDest.ChangeType(VT_UNKNOWN,this);
+  if(V_UNKNOWN(&varDest)!=NULL) V_UNKNOWN(&varDest)->AddRef();
+  return V_UNKNOWN(&varDest);
+}
+inline _variant_t::operator DECIMAL() const {
+  if(V_VT(this)==VT_DECIMAL) return V_DECIMAL(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_DECIMAL,this);
+  return V_DECIMAL(&varDest);
+}
+inline _variant_t::operator BYTE() const {
+  if(V_VT(this)==VT_UI1) return V_UI1(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_UI1,this);
+  return V_UI1(&varDest);
+}
+inline _variant_t::operator VARIANT() const throw() { return *(VARIANT*) this; }
+inline _variant_t::operator char() const {
+  if(V_VT(this)==VT_I1) return V_I1(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_I1,this);
+  return V_I1(&varDest);
+}
+
+inline _variant_t::operator unsigned short() const {
+  if(V_VT(this)==VT_UI2) return V_UI2(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_UI2,this);
+  return V_UI2(&varDest);
+}
+
+inline _variant_t::operator unsigned __LONG32() const {
+  if(V_VT(this)==VT_UI4) return V_UI4(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_UI4,this);
+  return V_UI4(&varDest);
+}
+#ifndef __CYGWIN__
+inline _variant_t::operator int() const {
+  if(V_VT(this)==VT_INT) return V_INT(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_INT,this);
+  return V_INT(&varDest);
+}
+inline _variant_t::operator unsigned int() const {
+  if(V_VT(this)==VT_UINT) return V_UINT(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_UINT,this);
+  return V_UINT(&varDest);
+}
+#endif
+__MINGW_EXTENSION inline _variant_t::operator __int64() const {
+  if(V_VT(this)==VT_I8) return V_I8(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_I8,this);
+  return V_I8(&varDest);
+}
+__MINGW_EXTENSION inline _variant_t::operator unsigned __int64() const {
+  if(V_VT(this)==VT_UI8) return V_UI8(this);
+  _variant_t varDest;
+  varDest.ChangeType(VT_UI8,this);
+  return V_UI8(&varDest);
+}
+inline _variant_t &_variant_t::operator=(const VARIANT &varSrc) {
+  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc)));
+  return *this;
+}
+inline _variant_t &_variant_t::operator=(const VARIANT *pSrc) {
+  if(!pSrc) { _com_issue_error(E_POINTER); }
+  else { _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc))); }
+  return *this;
+}
+inline _variant_t &_variant_t::operator=(const _variant_t &varSrc) {
+  _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc))));
+  return *this;
+}
+inline _variant_t &_variant_t::operator=(short sSrc) {
+  if(V_VT(this)==VT_I2) V_I2(this) = sSrc;
+  else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE);
+  else {
+    Clear();
+    V_VT(this) = VT_I2;
+    V_I2(this) = sSrc;
+  }
+  return *this;
+}
+inline _variant_t &_variant_t::operator=(__LONG32 lSrc) {
+  if(V_VT(this)==VT_I4) V_I4(this) = lSrc;
+  else if(V_VT(this)==VT_ERROR) V_ERROR(this) = lSrc;
+  else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE);
+  else {
+    Clear();
+    V_VT(this) = VT_I4;
+    V_I4(this) = lSrc;
+  }
+  return *this;
+}
+inline _variant_t &_variant_t::operator=(float fltSrc) {
+  if(V_VT(this)!=VT_R4) {
+    Clear();
+    V_VT(this) = VT_R4;
+  }
+  V_R4(this) = fltSrc;
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(double dblSrc)
+{
+  if(V_VT(this)==VT_R8) {
+    V_R8(this) = dblSrc;
+  }
+  else if(V_VT(this)==VT_DATE) {
+    V_DATE(this) = dblSrc;
+  }
+  else {
+
+    Clear();
+
+    V_VT(this) = VT_R8;
+    V_R8(this) = dblSrc;
+  }
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(const CY &cySrc)
+{
+  if(V_VT(this)!=VT_CY) {
+
+    Clear();
+
+    V_VT(this) = VT_CY;
+  }
+
+  V_CY(this) = cySrc;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(const _bstr_t &bstrSrc)
+{
+  _COM_ASSERT(V_VT(this)!=VT_BSTR || !((BSTR) bstrSrc) || V_BSTR(this)!=(BSTR) bstrSrc);
+
+  Clear();
+
+  V_VT(this) = VT_BSTR;
+
+  if(!bstrSrc) {
+    V_BSTR(this) = NULL;
+  }
+  else {
+    BSTR bstr = static_cast<wchar_t *>(bstrSrc);
+    V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr));
+
+    if(!(V_BSTR(this))) {
+      _com_issue_error(E_OUTOFMEMORY);
+    }
+  }
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(const wchar_t *pSrc)
+{
+  _COM_ASSERT(V_VT(this)!=VT_BSTR || !pSrc || V_BSTR(this)!=pSrc);
+
+  Clear();
+
+  V_VT(this) = VT_BSTR;
+
+  if(!pSrc) {
+    V_BSTR(this) = NULL;
+  }
+  else {
+    V_BSTR(this) = ::SysAllocString(pSrc);
+
+    if(!(V_BSTR(this))) {
+      _com_issue_error(E_OUTOFMEMORY);
+    }
+  }
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(const char *pSrc)
+{
+  _COM_ASSERT(V_VT(this)!=(VT_I1 | VT_BYREF) || !pSrc || V_I1REF(this)!=pSrc);
+
+  Clear();
+
+  V_VT(this) = VT_BSTR;
+  V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc);
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(IDispatch *pSrc)
+{
+  _COM_ASSERT(V_VT(this)!=VT_DISPATCH || pSrc==0 || V_DISPATCH(this)!=pSrc);
+
+  Clear();
+
+  V_VT(this) = VT_DISPATCH;
+  V_DISPATCH(this) = pSrc;
+
+  if(V_DISPATCH(this)!=NULL) {
+
+    V_DISPATCH(this)->AddRef();
+  }
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(bool boolSrc)
+{
+  if(V_VT(this)!=VT_BOOL) {
+
+    Clear();
+
+    V_VT(this) = VT_BOOL;
+  }
+
+  V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE);
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(IUnknown *pSrc)
+{
+  _COM_ASSERT(V_VT(this)!=VT_UNKNOWN || !pSrc || V_UNKNOWN(this)!=pSrc);
+
+  Clear();
+
+  V_VT(this) = VT_UNKNOWN;
+  V_UNKNOWN(this) = pSrc;
+
+  if(V_UNKNOWN(this)!=NULL) {
+
+    V_UNKNOWN(this)->AddRef();
+  }
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(const DECIMAL &decSrc)
+{
+  if(V_VT(this)!=VT_DECIMAL) {
+
+    Clear();
+  }
+
+  V_DECIMAL(this) = decSrc;
+  V_VT(this) = VT_DECIMAL;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(BYTE bSrc)
+{
+  if(V_VT(this)!=VT_UI1) {
+
+    Clear();
+
+    V_VT(this) = VT_UI1;
+  }
+
+  V_UI1(this) = bSrc;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(char cSrc)
+{
+  if(V_VT(this)!=VT_I1) {
+
+    Clear();
+
+    V_VT(this) = VT_I1;
+  }
+
+  V_I1(this) = cSrc;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(unsigned short usSrc)
+{
+  if(V_VT(this)!=VT_UI2) {
+
+    Clear();
+
+    V_VT(this) = VT_UI2;
+  }
+
+  V_UI2(this) = usSrc;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(unsigned __LONG32 ulSrc)
+{
+  if(V_VT(this)!=VT_UI4) {
+
+    Clear();
+
+    V_VT(this) = VT_UI4;
+  }
+
+  V_UI4(this) = ulSrc;
+
+  return *this;
+}
+
+#ifndef __CYGWIN__
+inline _variant_t &_variant_t::operator=(int iSrc)
+{
+  if(V_VT(this)!=VT_INT) {
+
+    Clear();
+
+    V_VT(this) = VT_INT;
+  }
+
+  V_INT(this) = iSrc;
+
+  return *this;
+}
+
+inline _variant_t &_variant_t::operator=(unsigned int uiSrc)
+{
+  if(V_VT(this)!=VT_UINT) {
+
+    Clear();
+
+    V_VT(this) = VT_UINT;
+  }
+
+  V_UINT(this) = uiSrc;
+
+  return *this;
+}
+#endif
+
+__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(__int64 i8Src) {
+  if(V_VT(this)!=VT_I8) {
+
+    Clear();
+
+    V_VT(this) = VT_I8;
+  }
+
+  V_I8(this) = i8Src;
+
+  return *this;
+}
+
+__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(unsigned __int64 ui8Src) {
+  if(V_VT(this)!=VT_UI8) {
+
+    Clear();
+
+    V_VT(this) = VT_UI8;
+  }
+
+  V_UI8(this) = ui8Src;
+
+  return *this;
+}
+
+inline bool _variant_t::operator==(const VARIANT &varSrc) const throw() {
+  return *this==&varSrc;
+}
+
+inline bool _variant_t::operator==(const VARIANT *pSrc) const throw()
+{
+  if(!pSrc) {
+    return false;
+  }
+
+  if(this==pSrc) {
+    return true;
+  }
+
+  if(V_VT(this)!=V_VT(pSrc)) {
+    return false;
+  }
+
+  switch (V_VT(this)) {
+case VT_EMPTY:
+case VT_NULL:
+  return true;
+
+case VT_I2:
+  return V_I2(this)==V_I2(pSrc);
+
+case VT_I4:
+  return V_I4(this)==V_I4(pSrc);
+
+case VT_R4:
+  return V_R4(this)==V_R4(pSrc);
+
+case VT_R8:
+  return V_R8(this)==V_R8(pSrc);
+
+case VT_CY:
+  return memcmp(&(V_CY(this)),&(V_CY(pSrc)),sizeof(CY))==0;
+
+case VT_DATE:
+  return V_DATE(this)==V_DATE(pSrc);
+
+case VT_BSTR:
+  return (::SysStringByteLen(V_BSTR(this))==::SysStringByteLen(V_BSTR(pSrc))) &&
+    (memcmp(V_BSTR(this),V_BSTR(pSrc),::SysStringByteLen(V_BSTR(this)))==0);
+
+case VT_DISPATCH:
+  return V_DISPATCH(this)==V_DISPATCH(pSrc);
+
+case VT_ERROR:
+  return V_ERROR(this)==V_ERROR(pSrc);
+
+case VT_BOOL:
+  return V_BOOL(this)==V_BOOL(pSrc);
+
+case VT_UNKNOWN:
+  return V_UNKNOWN(this)==V_UNKNOWN(pSrc);
+
+case VT_DECIMAL:
+  return memcmp(&(V_DECIMAL(this)),&(V_DECIMAL(pSrc)),sizeof(DECIMAL))==0;
+
+case VT_UI1:
+  return V_UI1(this)==V_UI1(pSrc);
+
+case VT_I1:
+  return V_I1(this)==V_I1(pSrc);
+
+case VT_UI2:
+  return V_UI2(this)==V_UI2(pSrc);
+
+case VT_UI4:
+  return V_UI4(this)==V_UI4(pSrc);
+
+case VT_INT:
+  return V_INT(this)==V_INT(pSrc);
+
+case VT_UINT:
+  return V_UINT(this)==V_UINT(pSrc);
+
+case VT_I8:
+  return V_I8(this)==V_I8(pSrc);
+
+case VT_UI8:
+  return V_UI8(this)==V_UI8(pSrc);
+
+default:
+  _com_issue_error(E_INVALIDARG);
+
+  }
+
+  return false;
+}
+
+inline bool _variant_t::operator!=(const VARIANT &varSrc) const throw()
+{
+  return !(*this==&varSrc);
+}
+
+inline bool _variant_t::operator!=(const VARIANT *pSrc) const throw()
+{
+  return !(*this==pSrc);
+}
+
+inline void _variant_t::Clear()
+{
+  _com_util::CheckError(::VariantClear(this));
+}
+
+inline void _variant_t::Attach(VARIANT &varSrc)
+{
+
+  Clear();
+
+  _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc));
+  V_VT(&varSrc) = VT_EMPTY;
+}
+
+inline VARIANT _variant_t::Detach()
+{
+  VARIANT varResult = *this;
+  V_VT(this) = VT_EMPTY;
+
+  return varResult;
+}
+
+inline VARIANT &_variant_t::GetVARIANT() throw()
+{
+  return *(VARIANT*) this;
+}
+
+inline VARIANT *_variant_t::GetAddress() {
+  Clear();
+  return (VARIANT*) this;
+}
+inline void _variant_t::ChangeType(VARTYPE vartype,const _variant_t *pSrc) {
+  if(!pSrc) pSrc = this;
+  if((this!=pSrc) || (vartype!=V_VT(this))) {
+    _com_util::CheckError(::VariantChangeType(static_cast<VARIANT*>(this),const_cast<VARIANT*>(static_cast<const VARIANT*>(pSrc)),0,vartype));
+  }
+}
+inline void _variant_t::SetString(const char *pSrc) { operator=(pSrc); }
+inline _variant_t::~_variant_t() throw() { ::VariantClear(this); }
+inline _bstr_t::_bstr_t(const _variant_t &var) : m_Data(NULL) {
+  if(V_VT(&var)==VT_BSTR) {
+    *this = V_BSTR(&var);
+    return;
+  }
+  _variant_t varDest;
+  varDest.ChangeType(VT_BSTR,&var);
+  *this = V_BSTR(&varDest);
+}
+inline _bstr_t &_bstr_t::operator=(const _variant_t &var) {
+  if(V_VT(&var)==VT_BSTR) {
+    *this = V_BSTR(&var);
+    return *this;
+  }
+  _variant_t varDest;
+  varDest.ChangeType(VT_BSTR,&var);
+  *this = V_BSTR(&varDest);
+  return *this;
+}
+
+extern _variant_t vtMissing;
+
+#ifndef _USE_RAW
+#define bstr_t _bstr_t
+#define variant_t _variant_t
+#endif
+
+#pragma pop_macro("new")
+
+/* We use _com_issue_error here, but we only provide its inline version in comdef.h,
+ * so we need to make sure that it's included as well. */
+#include <comdef.h>
+
+#endif /* __cplusplus */
+
+#endif
diff --git a/third_party/mingw_headers/new.h b/third_party/mingw_headers/new.h
new file mode 100644
index 00000000..f3c70971
--- /dev/null
+++ b/third_party/mingw_headers/new.h
@@ -0,0 +1,45 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#ifndef _INC_NEW
+#define _INC_NEW
+
+#ifdef __cplusplus
+
+#include <new>
+
+#include <crtdefs.h>
+
+#pragma push_macro("new")
+#undef new
+
+#ifndef __NOTHROW_T_DEFINED
+#define __NOTHROW_T_DEFINED
+#endif
+
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+#endif
+
+_CRTIMP int __cdecl _query_new_mode(void);
+_CRTIMP int __cdecl _set_new_mode(int _NewMode);
+
+#ifndef _PNH_DEFINED
+typedef int (__cdecl *_PNH)(size_t);
+#define _PNH_DEFINED
+#endif
+
+_CRTIMP _PNH __cdecl _query_new_handler(void);
+_CRTIMP _PNH __cdecl _set_new_handler(_PNH _NewHandler);
+
+#ifndef _NO_ANSI_NH_DEFINED
+#define _NO_ANSI_NEW_HANDLER ((new_handler)-1)
+#define _NO_ANSI_NEW_HANDLER_M ((_new_handler_m)-1)
+#define _NO_ANSI_NH_DEFINED
+#endif
+
+#pragma pop_macro("new")
+#endif
+#endif
diff --git a/tmux.c b/tmux.c
index 6659e1c3..a24818ae 100644
--- a/tmux.c
+++ b/tmux.c
@@ -65,7 +65,7 @@ getshell(void)
 	struct passwd	*pw;
 	const char	*shell;
 
-	shell = getenv("SHELL");
+	shell = GETENV_SHELL();
 	if (checkshell(shell))
 		return (shell);
 
@@ -328,7 +328,7 @@ find_home(void)
 	if (home != NULL)
 		return (home);
 
-	home = getenv("HOME");
+	home = GETENV_HOME();
 	if (home == NULL || *home == '\0') {
 		pw = getpwuid(getuid());
 		if (pw != NULL)
@@ -377,7 +377,7 @@ main(int argc, char **argv)
 		environ_put(global_environ, *var, 0);
 	if ((cwd = find_cwd()) != NULL)
 		environ_set(global_environ, "PWD", 0, "%s", cwd);
-	expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1);
+	expand_paths(TMUX_CONF_SEARCH_PATH(), &cfg_files, &cfg_nfiles, 1);
 
 	while ((opt = getopt(argc, argv, "2c:CDdf:lL:NqS:T:uUvV")) != -1) {
 		switch (opt) {
diff --git a/tmux.h b/tmux.h
index 0753cb27..ff3f0fda 100644
--- a/tmux.h
+++ b/tmux.h
@@ -81,9 +81,6 @@ struct winlink;
 #ifndef TMUX_CONF
 #define TMUX_CONF "/etc/tmux.conf:~/.tmux.conf"
 #endif
-#ifndef TMUX_SOCK
-#define TMUX_SOCK "$TMUX_TMPDIR:" _PATH_TMP
-#endif
 #ifndef TMUX_SOCK_PERM
 #define TMUX_SOCK_PERM (7 /* o+rwx */)
 #endif
diff --git a/tty-term.c b/tty-term.c
index d4223497..e79c33bb 100644
--- a/tty-term.c
+++ b/tty-term.c
@@ -683,8 +683,9 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
 	u_int					 i;
 	const char				*s;
 	char					 tmp[11];
+	int					 retval = ERR;
 
-	if (setupterm((char *)name, fd, &error) != OK) {
+	if ((retval = setupterm((char *)name, fd, &error)) != OK) {
 		switch (error) {
 		case 1:
 			xasprintf(cause, "can't use hardcopy terminal: %s",
@@ -695,13 +696,25 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
 			    name);
 			break;
 		case -1:
-			xasprintf(cause, "can't find terminfo database");
-			break;
+#ifdef WIN32_PLATFORM
+			if ((retval = setupterm("#win32con", fd, &error)) != OK)
+			{
+			    xasprintf(cause, "can't set up Win32 console");
+			    break;
+			}
+#else
+			{
+			    xasprintf(cause, "can't find terminfo database");
+			    break;
+			}
+#endif
 		default:
 			xasprintf(cause, "unknown error");
 			break;
 		}
-		return (-1);
+
+		if (retval != OK)
+		    return (-1);
 	}
 
 	*ncaps = 0;