diff --git a/src/sbbs3/dosxtrn/dosxtrn.c b/src/sbbs3/dosxtrn/dosxtrn.c
index b90e81d669544e63ed3e9982adee069642dd163c..541d3a953eab47468c36dcc652cc4ac2f42bba02 100644
--- a/src/sbbs3/dosxtrn/dosxtrn.c
+++ b/src/sbbs3/dosxtrn/dosxtrn.c
@@ -1,9 +1,5 @@
-/* dosxtrn.c */
-
 /* Synchronet External DOS Program Launcher (16-bit MSVC 1.52c project) */
 
-/* $Id: dosxtrn.c,v 1.25 2020/04/15 08:22:33 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -42,7 +38,6 @@
 #include <dos.h>			/* _dos_set/getvect() */
 #include <windows.h>		/* BOOL, etc. */
 #include "vdd_func.h"
-#include "execvxd.h"
 #include "isvbop.h"			/* ddk\inc */
 #include "fossdefs.h"
 #include "../git_branch.h"
@@ -65,7 +60,6 @@ static void truncsp(char *str)
 }
 short	vdd=0;
 BYTE	node_num=0;
-int		mode=0;
 char	id_string[128];
 #ifdef DEBUG_INT_CALLS
 ulong	int14calls=0;
@@ -137,48 +131,6 @@ static int vdd_op(BYTE op)
 	return(retval);
 }
 
-union REGS inregs;
-struct SREGS sregs;
-BOOL inside_int14=FALSE;
-
-/* This function is only necessary for naughty programs that call the vector
-   directly instead of issuing an interrupt 
-*/
-void interrupt win95int14(
-	unsigned _es, unsigned _ds,
-	unsigned _di, unsigned _si,
-	unsigned _bp, unsigned _sp,
-	unsigned _bx, unsigned _dx,
-	unsigned _cx, unsigned _ax,
-    unsigned flags )
-{
-	union REGS outregs;
-
-	/* prevent recursion, just incase the VXD isn't handling int14h */
-	if(inside_int14)	
-		return;
-
-	inside_int14=TRUE;
-
-	inregs.x.ax=_ax;
-	inregs.x.bx=_bx;
-	inregs.x.cx=_cx;
-	inregs.x.dx=_dx;
-	inregs.x.si=_si;
-	inregs.x.di=_di;
-	inregs.x.cflag=flags;
-
-	sregs.es=_es;
-	sregs.ds=_ds;
-
-	int86x(0x14,&inregs,&outregs,&sregs);
-
-	/* FOSSIL driver only touches these AX and BX */
-	_ax= outregs.x.ax;
-	_bx= outregs.x.bx;
-
-	inside_int14=FALSE;
-}
 
 void vdd_getstatus(vdd_status_t* status)
 {
@@ -500,8 +452,8 @@ int main(int argc, char **argv)
 	char*	envvar[MAX_ENVVARS];
 	char*	arg[MAX_ARGS];
 	int		i,c,d,envnum=0;
+	int		mode = SBBSEXEC_MODE_UNSPECIFIED;
 	FILE*	fp;
-	BOOL	NT=FALSE;
 	BOOL	x64=FALSE;
 	BOOL	success=FALSE;
 	WORD	buf_seg;
@@ -513,7 +465,7 @@ int main(int argc, char **argv)
 			,"%s - Copyright %s Rob Swindell\n"
 			,id_string, __DATE__+7);
 		fprintf(stderr
-			,"usage: dosxtrn <path/dosxtrn.env> [NT|95|x64] [node_num] [mode]\n");
+			,"usage: dosxtrn <path/dosxtrn.env> [NT|x64] [node_num] [mode]\n");
 		return(1);
 	}
 
@@ -524,16 +476,17 @@ int main(int argc, char **argv)
 	DllName=dll;
 
 	if(argc>2) {
-		if(strcmp(argv[2],"NT") == 0)
-			NT=TRUE;
-		else if(strcmp(argv[2],"x64") == 0)
-			NT=TRUE, x64=TRUE;
+		if(strcmp(argv[2],"x64") == 0)
+			x64=TRUE;
 	}
 	if(argc>3)
 		node_num=atoi(argv[3]);
 	if(argc>4)
 		mode=atoi(argv[4]);
 
+	if(mode == SBBSEXEC_MODE_UNSPECIFIED)
+		mode = SBBSEXEC_MODE_DEFAULT;
+
 	if((fp=fopen(argv[1],"r"))==NULL) {
 		fprintf(stderr,"!Error opening %s\n",argv[1]);
 		return(2);
@@ -574,76 +527,71 @@ int main(int argc, char **argv)
 	((BYTE*)int14stub)[7] = FOSSIL_SIGNATURE>>8;	/* FOSSIL sig (MSB) */
 	((BYTE*)int14stub)[8] = FOSSIL_FUNC_HIGHEST;	/* FOSSIL highest func supported */
 
-	if(NT) {	/* Windows NT/2000 */
-
-		for(i=0;i<2;i++) {
-
-			/* Register VDD */
-       		_asm {
-				push	es
-				push	ds
-				pop		es
-				mov     si, DllName		; ds:si = dll name
-				mov     di, InitFunc    ; es:di = init routine
-				mov     bx, DispFunc    ; ds:bx = dispatch routine
+	for(i=0;i<2;i++) {
+
+		/* Register VDD */
+       	_asm {
+			push	es
+			push	ds
+			pop		es
+			mov     si, DllName		; ds:si = dll name
+			mov     di, InitFunc    ; es:di = init routine
+			mov     bx, DispFunc    ; ds:bx = dispatch routine
+		};
+		if(!x64) {	// NTVDMx64 (based on an older Windows NTVDM) requires an init routine
+			_asm {	/* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
+				xor		di,di
+				mov		es,di
 			};
-			if(!x64) {	// NTVDMx64 (based on an older Windows NTVDM) requires an init routine
-				_asm {	/* Vista work-around, apparently doesn't support an InitFunc (RegisterModule fails with AX=1) */
-					xor		di,di
-					mov		es,di
-				};
-			}
-			RegisterModule();
-			_asm {
-				mov		vdd, ax
-				jc		err
-				mov		success, TRUE
-				err:
-				pop		es
-			}
-			if(success)
-				break;
-			DllName=VDD_FILENAME;	/* try again with no path (for Windows Vista) */
 		}
-		if(!success) {
-			fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
-			return(-1);
+		RegisterModule();
+		_asm {
+			mov		vdd, ax
+			jc		err
+			mov		success, TRUE
+			err:
+			pop		es
 		}
+		if(success)
+			break;
+		DllName=VDD_FILENAME;	/* try again with no path (for Windows Vista) */
+	}
+	if(!success) {
+		fprintf(stderr,"Error %d loading %s\n",vdd,DllName);
+		return(-1);
+	}
 
 #if 0
-		fprintf(stderr,"vdd handle=%d\n",vdd);
-		fprintf(stderr,"mode=%d\n",mode);
+	fprintf(stderr,"vdd handle=%d\n",vdd);
+	fprintf(stderr,"mode=%d\n",mode);
 #endif
-		vdd_str(VDD_LOAD_INI_FILE, exec_dir);
+	vdd_str(VDD_LOAD_INI_FILE, exec_dir);
 
-		vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
+	vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
 
-		sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
-		vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
+	vdd_str(VDD_DEBUG_OUTPUT, str);
 
-		i=vdd_op(VDD_OPEN);
-		if(i) {
-			fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
-			UnRegisterModule();
-			return(-1);
-		}
-		oldint16=_dos_getvect(0x16);
-		oldint21=_dos_getvect(0x21);
-		oldint29=_dos_getvect(0x29);
-		if(mode==SBBSEXEC_MODE_FOSSIL) {
-			*(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3;	/* jmp offset */
-			_dos_setvect(0x14,(void(interrupt *)())int14stub); 
-		}
-		_dos_setvect(0x21,winNTint21); 
-		if(mode&SBBSEXEC_MODE_DOS_IN)
-			_dos_setvect(0x16,winNTint16); 
-		if(mode&SBBSEXEC_MODE_DOS_OUT) 
-			_dos_setvect(0x29,winNTint29); 
+	if(mode & SBBSEXEC_MODE_UART)
+		vdd_op(VDD_VIRTUALIZE_UART);
+	i=vdd_op(VDD_OPEN);
+	if(i) {
+		fprintf(stderr,"!VDD_OPEN ERROR: %d\n",i);
+		UnRegisterModule();
+		return(-1);
 	}
-	else if(mode==SBBSEXEC_MODE_FOSSIL)	{ /* Windows 95/98/Millennium */
-		*(WORD*)((BYTE*)int14stub+1) = (WORD)win95int14 - (WORD)&int14stub - 3;		/* jmp offset */
+	oldint16=_dos_getvect(0x16);
+	oldint21=_dos_getvect(0x21);
+	oldint29=_dos_getvect(0x29);
+	if(mode & SBBSEXEC_MODE_FOSSIL) {
+		*(WORD*)((BYTE*)int14stub+1) = (WORD)winNTint14 - (WORD)&int14stub - 3;	/* jmp offset */
 		_dos_setvect(0x14,(void(interrupt *)())int14stub); 
 	}
+	_dos_setvect(0x21,winNTint21); 
+	if(mode&SBBSEXEC_MODE_DOS_IN)
+		_dos_setvect(0x16,winNTint16); 
+	if(mode&SBBSEXEC_MODE_DOS_OUT) 
+		_dos_setvect(0x29,winNTint29); 
 
 	_heapmin();
 	i=_spawnvp(_P_WAIT, arg[0], arg);
@@ -659,46 +607,43 @@ int main(int argc, char **argv)
 	/* Restore original ISRs */
 	_dos_setvect(0x14,oldint14);
 
-	if(NT) {
-		vdd_op(VDD_CLOSE);
+	vdd_op(VDD_CLOSE);
 
-		_dos_setvect(0x16,oldint16);
-		_dos_setvect(0x21,oldint21);
-		_dos_setvect(0x29,oldint29);
+	_dos_setvect(0x16,oldint16);
+	_dos_setvect(0x21,oldint21);
+	_dos_setvect(0x29,oldint29);
 
-		sprintf(str,"%s returned %d", arg[0], i);
-		vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"%s returned %d", arg[0], i);
+	vdd_str(VDD_DEBUG_OUTPUT, str);
 
 #ifdef DEBUG_INT_CALLS
-		sprintf(str,"int14h calls: %lu", int14calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
-		sprintf(str,"int16h calls: %lu", int16calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
-		sprintf(str,"int21h calls: %lu", int21calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
-		sprintf(str,"int29h calls: %lu", int29calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"int14h calls: %lu", int14calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"int16h calls: %lu", int16calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"int21h calls: %lu", int21calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
+	sprintf(str,"int29h calls: %lu", int29calls);	vdd_str(VDD_DEBUG_OUTPUT, str);
 #endif
 #ifdef DEBUG_DOS_CALLS
-		for(i=0;i<0x100;i++) {
-			if(dos_calls[i]>100) {
-				sprintf(str,"int21h function %02X calls: %u"
-					,i, dos_calls[i]);
-				vdd_str(VDD_DEBUG_OUTPUT, str);
-			}
+	for(i=0;i<0x100;i++) {
+		if(dos_calls[i]>100) {
+			sprintf(str,"int21h function %02X calls: %u"
+				,i, dos_calls[i]);
+			vdd_str(VDD_DEBUG_OUTPUT, str);
 		}
+	}
 #endif
 #ifdef DEBUG_FOSSIL_CALLS
-		for(i=0;i<0x100;i++) {
-			if(fossil_calls[i]>0) {
-				sprintf(str,"int14h function %02X (%-10s) calls: %lu"
-					,i, fossil_func(i), fossil_calls[i]);
-				vdd_str(VDD_DEBUG_OUTPUT, str);
-			}
+	for(i=0;i<0x100;i++) {
+		if(fossil_calls[i]>0) {
+			sprintf(str,"int14h function %02X (%-10s) calls: %lu"
+				,i, fossil_func(i), fossil_calls[i]);
+			vdd_str(VDD_DEBUG_OUTPUT, str);
 		}
+	}
 #endif
 
-		/* Unregister VDD */
-		_asm mov ax, vdd;
-		UnRegisterModule();
-
-	}
+	/* Unregister VDD */
+	_asm mov ax, vdd;
+	UnRegisterModule();
 
 	return(i);
 }
diff --git a/src/sbbs3/execvxd.h b/src/sbbs3/execvxd.h
deleted file mode 100644
index 3007c2bc42861c61922d10b4f5d1f22ca1c73642..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* execvxd.h */
-
-/* Synchronet FOSSIL driver (VxD) for Windows 9x API */
-
-/* $Id: execvxd.h,v 1.1.1.1 2000/10/10 11:26:23 rswindell Exp $ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html		*
- *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-#define SBBSEXEC_VXD	"sbbsexec.vxd"
-
-#define SBBSEXEC_IOCTL_START		0x8001
-#define SBBSEXEC_IOCTL_COMPLETE		0x8002
-#define SBBSEXEC_IOCTL_READ			0x8003
-#define SBBSEXEC_IOCTL_WRITE		0x8004
-#define SBBSEXEC_IOCTL_DISCONNECT	0x8005
-#define SBBSEXEC_IOCTL_STOP			0x8006
-
-#define SBBSEXEC_MODE_FOSSIL		(0)
-#define SBBSEXEC_MODE_DOS_IN		(1<<0)
-#define SBBSEXEC_MODE_DOS_OUT		(1<<1)
-#define SBBSEXEC_MODE_UART			(1<<2)
-
-enum {
-	 SBBSEXEC_ERROR_INUSE=1
-	,SBBSEXEC_ERROR_INBUF
-	,SBBSEXEC_ERROR_INDATA
-	,SBBSEXEC_ERROR_IOCTL
-	,SBBSEXEC_ERROR_OUTBUF
-};
-
-typedef struct {
-	DWORD	mode;
-	HANDLE	event;
-} sbbsexec_start_t;
-
-extern HANDLE exec_mutex;
diff --git a/src/sbbs3/execvxd/c.bat b/src/sbbs3/execvxd/c.bat
deleted file mode 100755
index 90a600f40431913fcc18829dbfa923c5d1ae6487..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/c.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@echo off
-xcopy sbbsexec.vxd c:\sbbs\exec
-
diff --git a/src/sbbs3/execvxd/debugout.h b/src/sbbs3/execvxd/debugout.h
deleted file mode 100644
index a018c3fab90b4fadfcc67ddfc413c8bb13b46716..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/debugout.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* DEBUGOUT.H */
-
-/* $Id: debugout.h,v 1.1.1.1 2000/10/10 11:27:22 rswindell Exp $ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html		*
- *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-#ifndef _DEBUGOUT_H_
-#define _DEBUGOUT_H_
-
-#ifndef DEBUG_VAR		// Pre-define to use different/dynamic debug enable var
-#define DEBUG_VAR 0x1
-#endif
-
-#ifndef DEVICENAME		// Pre-define to display devicename on output
-#define DEVICENAME "DBTRACE"
-#endif
-
-#ifndef DBTRACEDPF		// Pre-define if using other printf type function
-#define DBTRACEDPF dprintf
-#endif
-
-#ifndef DBTFILEOFF		// Pre-define if __FILE__ offset required != 2
-#define DBTFILEOFF 2
-#endif
-
-#ifndef TEXT			// Windows Unicode support
-#define TEXT(x)		x
-#endif
-
-#ifndef DBTRACENL		// Pre-define if \n required
-#define DBTRACENL TEXT("")
-#endif
-
-#if !defined(DBG) && !defined(DEBUG)
-
-#define DBTRACE(b,s);			{ /* DBTRACE */ }
-#define DBTRACEd(b,s,d);		{ /* DBTRACE */ }
-#define DBTRACEs(b,s,t);		{ /* DBTRACE */ }
-#define DBTRACEx(b,s,x);		{ /* DBTRACE */ }
-#define DBTRACEdd(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACEds(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACEsd(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACEdx(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACExd(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACExx(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACEsx(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACExs(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACEss(b,s,x,y); 	{ /* DBTRACE */ }
-#define DBTRACExxd(b,s,x,y,z);	{ /* DBTRACE */ }
-#define DBTRACEddx(b,s,x,y,z);	{ /* DBTRACE */ }
-#define DBTRACEdds(b,s,x,y,z);	{ /* DBTRACE */ }
-#define DBTRACExdd(b,s,x,y,z);	{ /* DBTRACE */ }
-#define DBTRACExxx(b,s,x,y,z);	{ /* DBTRACE */ }
-#define DBTRACExsx(b,s,x,y,z);	{ /* DBTRACE */ }
-
-#else /* DBG or DEBUG */
-
-#define DBTRACE(b,s);			{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s%s") \
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s)					\
-										,DBTRACENL); } }
-#define DBTRACEd(b,s,d);		{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ") \
-                                    	TEXT("%d%s")						\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),d						\
-										,DBTRACENL); } }
-#define DBTRACEs(b,s,t);		{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%s%s") 						\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),t						\
-										,DBTRACENL); } }
-#define DBTRACEx(b,s,x);		{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%02X%s")                            \
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x						\
-										,DBTRACENL); } }
-#define DBTRACEdd(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-										TEXT("%d %d%s")                     \
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACEds(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%d %s%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACEsd(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%s %d%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACEdx(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%d %X%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACExd(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %d%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACExx(b,s,x,y); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %X%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,y 					\
-										,DBTRACENL); } }
-#define DBTRACEsx(b,s,t,x); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%s %X%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),t,x 					\
-										,DBTRACENL); } }
-#define DBTRACExs(b,s,x,t); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %s%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,t 					\
-										,DBTRACENL); } }
-#define DBTRACEss(b,s,x,t); 	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%s %s%s")							\
-										,DEVICENAME,TEXT(__FILE__+DBTFILEOFF) 	\
-										,__LINE__,TEXT(s),x,t 					\
-										,DBTRACENL); } }
-#define DBTRACEddx(b,s,x,y,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%d %d %X%s")                  \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,y,z							\
-										,DBTRACENL); } }
-#define DBTRACEdds(b,s,x,y,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%d %d %s%s")                  \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,y,z							\
-										,DBTRACENL); } }
-#define DBTRACExdd(b,s,x,y,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %d %d%s")                        \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,y,z							\
-                                        ,DBTRACENL); } }
-#define DBTRACExxd(b,s,x,y,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %X %d%s")                        \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,y,z							\
-                                        ,DBTRACENL); } }
-#define DBTRACExxx(b,s,x,y,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %X %X%s")                        \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,y,z							\
-										,DBTRACENL); } }
-#define DBTRACExsx(b,s,x,t,z);	{ if(DEBUG_VAR&(1<<b)) {					\
-									DBTRACEDPF(TEXT("%-8s (%-12.12s %4d): %s: ")\
-                                    	TEXT("%X %s %X%s")                        \
-										,DEVICENAME 						\
-										,TEXT(__FILE__+DBTFILEOFF),__LINE__		\
-										,TEXT(s),x,t,z							\
-										,DBTRACENL); } }
-
-#endif
-
-#endif	// Don't add anything after this line
diff --git a/src/sbbs3/execvxd/makefile b/src/sbbs3/execvxd/makefile
deleted file mode 100644
index f585a6c75af0f3404ffc2d202ec87ca870b56b0b..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# makefile for SBBSEXEC.VXD
-
-DEVICENAME = SBBSEXEC
-FRAMEWORK = CPP
-XFLAGS = -I..
-OBJECTS = sbbsexec.obj ringbuf.obj
-SOURCEINCPATH = ..
-DEBUG = 0
-
-DYNAMIC = 1
-
-!include $(VTOOLSD)\include\vtoolsd.mak
-!include $(VTOOLSD)\include\vxdtarg.mak
-
-sbbsexec.obj:	sbbsexec.cpp makefile
-ringbuf.obj:	..\ringbuf.c ..\ringbuf.h
diff --git a/src/sbbs3/execvxd/sbbsexec.cpp b/src/sbbs3/execvxd/sbbsexec.cpp
deleted file mode 100644
index 75fd82271cb2cd7afd80d17a5ef1b498d1e61887..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/sbbsexec.cpp
+++ /dev/null
@@ -1,876 +0,0 @@
-// SBBSEXEC.cpp - SBBSEXEC.VXD main module
-
-/* Synchronet Windows 9X FOSSIL driver (requires VtoolsD C++ framework) */
-
-/* $Id: sbbsexec.cpp,v 1.3 2018/07/24 01:11:52 rswindell Exp $ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
- *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-
-#define DEVICE_MAIN
-#include "sbbsexec.h"
-#include "debugout.h"
-#include "..\ringbuf.h"
-
-#define RINGBUF_SIZE_IN		10000
-#define RINGBUF_SIZE_OUT	10000
-
-#undef	DEVICENAME
-#define DEVICENAME "SBBSEXEC"    // For debug output
-
-#include LOCKED_CODE_SEGMENT
-#include LOCKED_DATA_SEGMENT
-
-#define MAX_VM 250
-
-typedef struct {
-	VMHANDLE	handle;
-    SEMHANDLE	input_sem;
-    SEMHANDLE	output_sem;
-	DWORD		mode;
-	BOOL		online;
-	BOOL		overrun;
-	RingBuf		in;
-	RingBuf		out;
-} vm_t;
-
-vm_t vm[MAX_VM];
-
-Declare_Virtual_Device(SBBSExec)
-
-//////////////////////////////////////////////////////////////////////////
-#include LOCKED_CODE_SEGMENT
-#include LOCKED_DATA_SEGMENT
-
-vm_t*				new_vm;
-sbbsexec_start_t	start;
-
-vm_t* find_vm(VMHANDLE hVM)
-{
-	int i;
-
-	for(i=0;i<MAX_VM;i++)
-		if(vm[i].handle==hVM)
-			return(&vm[i]);
-#if 0
-	if(hVM!=Get_Sys_VM_Handle()) {
-		DBTRACEx(0,"!VM NOT FOUND",hVM);
-	}
-#endif
-	return(NULL);
-}
-
-BOOL SBBSExec::OnSysDynamicDeviceInit()
-{
-	DBTRACE(0,"OnSysDynamicDeviceInit");
-
-	return(OnDeviceInit(NULL,NULL));
-}
-
-
-BOOL SBBSExec::OnDeviceInit(VMHANDLE hSysVM, PCHAR pszCmdTail)
-{
-	DBTRACE(0,"SBBSExec::OnDeviceInit");
-
-	pInt10 = NULL;	// BIOS I/O
-	pInt14 = NULL;	// FOSSIL
-	pInt16 = NULL;	// Keyboard input
-	pInt21 = NULL;	// DOS I/O
-	pInt29 = NULL;	// Direct console I/O (PKZIP/UNZIP)
-
-	memset(&start,0,sizeof(start));
-#if 1
-
-
-	if ( (pInt21 = new SBBSExecInt21()) == NULL) {
-		DBTRACE(0,"!Failed to create int 21 handler");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( !pInt21->hook()) {
-		DBTRACE(0,"!Failed to hook int 21");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( (pInt29 = new SBBSExecInt29()) == NULL) {
-		DBTRACE(0,"!Failed to create int 29 handler");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( !pInt29->hook()) {
-		DBTRACE(0,"!Failed to hook int 29");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( (pInt16 = new SBBSExecInt16()) == NULL) {
-		DBTRACE(0,"!Failed to create int 16 handler");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( !pInt16->hook()) {
-		DBTRACE(0,"!Failed to hook int 16");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( (pInt14 = new SBBSExecInt14()) == NULL) {
-		DBTRACE(0,"!Failed to create int 14 handler");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( !pInt14->hook()) {
-		DBTRACE(0,"!Failed to hook int 14");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( (pInt10 = new SBBSExecInt10()) == NULL) {
-		DBTRACE(0,"!Failed to create int 10 handler");
-		UnhookInts();
-		return(FALSE);
-	}
-
-	if ( !pInt10->hook()) {
-		DBTRACE(0,"!Failed to hook int 10");
-		UnhookInts();
-		return(FALSE);
-	}
-
-#endif
-
-	return TRUE;
-}
-
-//****************************************************************************
-//****************************************************************************
-VOID SBBSExec::OnSystemExit(VMHANDLE hSysVM)
-{
-	DBTRACE(0,"OnSystemExit");
-	OnSysDynamicDeviceExit();
-}
-
-void SBBSExec::UnhookInts()
-{
-
-	if(pInt10!=NULL) {
-		pInt10->unhook();
-		delete pInt10;
-		pInt10=NULL;
-	}
-
-	if(pInt14!=NULL) {
-		pInt14->unhook();
-		delete pInt14;
-		pInt14=NULL;
-	}
-
-	if(pInt16!=NULL) {
-		pInt16->unhook();
-		delete pInt16;
-		pInt16=NULL;
-	}
-
-	if(pInt21!=NULL) {
-		pInt21->unhook();
-		delete pInt21;
-		pInt21=NULL;
-	}
-
-	if(pInt29!=NULL) {
-		pInt29->unhook();
-		delete pInt29;
-		pInt29=NULL;
-	}
-}
-
-//****************************************************************************
-// Handle control message SYS_DYNAMIC_DEVICE_EXIT
-//****************************************************************************
-BOOL SBBSExec::OnSysDynamicDeviceExit()
-{
-	DBTRACE(0,"OnSysDynamicDeviceExit");
-
-	UnhookInts();
-
-	return(TRUE);
-}
-
-//////////////////////////////////////////////////////////////////////////
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BOOL SBBSExec::OnCreateVM(VMHANDLE hVM)
-{
-	DBTRACExd(0,"CreateVM, handle, time",hVM,Get_System_Time());
-	DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());
-
-	if(start.event) {
-		new_vm=find_vm(NULL);
-		if(new_vm==NULL) {
-			DBTRACE(0,"!NO AVAILABLE VM structures");
-			return(FALSE);
-		}
-		new_vm->handle=hVM;
-		new_vm->mode=start.mode;
-		new_vm->online = true;
-		new_vm->overrun = false;
-		new_vm->input_sem = NULL;
-		new_vm->output_sem = NULL;
-
-		if(RingBufInit(&new_vm->in, RINGBUF_SIZE_IN)!=0
-			|| RingBufInit(&new_vm->out, RINGBUF_SIZE_OUT)!=0) {
-			DBTRACE(0,"!FAILED to create I/O buffers");
-			return(FALSE);
-		}
-		if(!VWIN32_SetWin32Event(start.event)) {
-			DBTRACEx(0,"!FAILED TO SET EVENT handle", start.event);
-			return(FALSE);
-		}
-		if(!VWIN32_CloseVxDHandle(start.event)) {
-			DBTRACEx(0,"!FAILED TO CLOSE EVENT handle", start.event);
-			return(FALSE);
-		}
-		start.event=0;
-	}
-	return(TRUE);
-}
-
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SBBSExecInt29::SBBSExecInt29() : VPreChainV86Int(0x29)
-{
-	DBTRACE(0,"SBBSExecInt29 constructor");
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BOOL SBBSExecInt29::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
-{
-	vm_t* vm = find_vm(hVM);
-
-	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
-		return(FALSE); // Tells VMM that interrupt was not handled
-	}
-
-    if(!RingBufFree(&vm->out)) {
-        DBTRACEx(0,"!Int29 OUTPUT BUFFER OVERFLOW, hVM", hVM);
-        vm->overrun=true;
-        return(FALSE);
-    }
-	DBTRACEx(1,"Int29 OUTPUT", _clientAL);
-
-    BYTE ch=_clientAL;
-    RingBufWrite(&vm->out,&ch,1);
-    vm->overrun=false;
-
-	return(FALSE);
-}
-
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SBBSExecInt21::SBBSExecInt21() : VPreChainV86Int(0x21)
-{
-	DBTRACE(0,"SBBSExecInt21 constructor");
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BOOL SBBSExecInt21::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
-{
-	BYTE	ch;
-	BYTE*	buffer;
-	WORD	buflen;
-	vm_t*	vm = find_vm(hVM);
-
-	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
-#if 0
-		if(vm && !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
-			DBTRACEx(0,"Int21 on unsupported VM", hVM);
-		}
-#endif
-		return(FALSE); // Tells VMM that interrupt was not handled
-	}
-	DBTRACEx(1,"Int21 function", _clientAH);
-
-	DWORD avail = RingBufFree(&vm->out);
-
-    switch(_clientAH) {
-    	case 0x01:
-            DBTRACE(0,"!Int21 Char input WITH echo");
-            break;
-        case 0x06:	// Direct console I/O
-			DBTRACEx(0,"DOS DIRECT CONSOLE IO, DL", _clientDL);
-			if(_clientDL==0xff)  {
-				avail=RingBufFull(&vm->in);
-				if(avail) {
-					DBTRACEd(0,"avail",avail);
-		            RingBufRead(&vm->in, &ch, 1);
-					_clientFlags&=~(1<<6);	// clear zero flag
-					_clientAX=ch;
-					return(TRUE);
-				}
-				break;
-			}
-			// fall-through
-    	case 0x02:	// Character output
-			DBTRACEx(1,"Int21 function", _clientAH);
-            if(!avail) {
-                DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
-                vm->overrun=true;
-				break;
-            }
-            ch=_clientDL;
-            RingBufWrite(&vm->out,&ch,1);
-            vm->overrun=false;
-			break;
-		case 0x09:	// Display string
-			DBTRACE(0,"!Int21 func 09 - DISPLAY STRING");
-			break;
-		case 0x0A:	// Buffered keyboard input
-			DBTRACE(0,"Int21 Func 0A - Buffered Keyboard Input");
-			/* Need to get a string from the user, echo, and copy to DS:DX */
-			/* byte 0 = max length, byte 1 = actual read (minus CR) */
-			break;
-        case 0x40:	// Write file or device
-			if(_clientBX!=1 && _clientBX!=2) {	// !stdout and !stderr
-            	DBTRACEd(1,"!Int21 write to unsupported device", _clientBX);
-				break;
-            }
-			DBTRACEdd(1,"Int21 write file", _clientBX, _clientCX);
-            buffer = (BYTE*)MAPFLAT(CRS.Client_DS, CWRS.Client_DX);
-            buflen = _clientCX;
-            if(avail<buflen) {
-                DBTRACEd(0,"!OUTPUT BUFFER OVERFLOW, avail", avail);
-                vm->overrun=true;
-                if(!avail)
-					break;
-                buflen=avail;
-            }
-            RingBufWrite(&vm->out,buffer,buflen);
-            vm->overrun=false;
-            break;
-    }
-
-	return(FALSE);	// Tells VMM that interrupt was not handled
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SBBSExecInt16::SBBSExecInt16() : VPreChainV86Int(0x16)
-{
-	DBTRACE(0,"SBBSExecInt16 constructor");
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BOOL SBBSExecInt16::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
-{
-	BYTE 	ch;
-    DWORD   avail;
-	vm_t*	vm = find_vm(hVM);
-
-	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_IN)) {
-		return(FALSE); // Tells VMM that interrupt was not handled
-	}
-
-//    DBTRACExx(0,"Int16 (hVM, AX)", hVM, _clientAX);
-
-	avail=RingBufFull(&vm->in);
- 	switch(_clientAH) {
-    	case 0x00:	// Read char from keyboard
-        case 0x10:	// Read char from enhanced keyboard
-			if(avail) {
-	            RingBufRead(&vm->in, &ch, 1);
-				_clientAX=ch;
-				return(TRUE);
-			}
-			break;
-    	case 0x01:	// Get keyboard status
-        case 0x11:	// Get enhanced keyboard status
-			if(avail) {
-                RingBufPeek(&vm->in, &ch, 1);
-                _clientFlags&=~(1<<6);	// clear zero flag
-                _clientAX=ch;
-				return(TRUE);
-    	    }
-	        break;
-        default:
-		    DBTRACEx(0,"!UNHANDLED INT16 function", _clientAH);
-            break;
-	}
-
-    return(FALSE);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SBBSExecInt14::SBBSExecInt14() : VPreChainV86Int(0x14)
-{
-	DBTRACE(0,"SBBSExecInt14 constructor");
-}
-
-WORD PortStatus(vm_t* vm)
-{
-	WORD status=0x0008;			// AL bit 3 (change in DCD) always set
-
-	if(vm->online)				// carrier detect
-		status|=0x0080;			// DCD
-
-	if(RingBufFull(&vm->in))	// receive data ready 
-		status|=0x0100;			// RDA
-
-	if(vm->overrun)				// overrun error detected
-		status|=0x0200;			// OVRN
-
-	if(RingBufFree(&vm->out)>	// room available in output buffer
-		RINGBUF_SIZE_OUT/2)	
-		status|=0x2000;			// THRE
-
-	if(!RingBufFull(&vm->out))	// output buffer is empty
-		status|=0x4000;			// TSRE
-
-	return(status);
-}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const char* fossil_id="Synchronet SBBSEXEC.VXD Fossil";
-BOOL SBBSExecInt14::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
-{
-	BYTE*	buffer;
-	BYTE	ch;
-	WORD	buflen;
-    WORD	rd,wr;
-    WORD	avail;
-	vm_t*	vm = find_vm(hVM);
-
-	if(vm==NULL || vm->mode!=SBBSEXEC_MODE_FOSSIL) {
-		return(FALSE); // Tells VMM that interrupt was not handled
-	}
-
-
-	DBTRACEx(4,"Int14 func",_clientAH);
-
-	switch(_clientAH) {
-		case 0x00:	/* Initialize/Set baud rate */
-        	DBTRACE(0,"Int14 init");
-			_clientAX=PortStatus(vm);
-			break;
-		case 0x01: /* write char to com port */
-        	if(RingBufFree(&vm->out)<2) {
-            	DBTRACEx(1,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
-            	vm->output_sem=Create_Semaphore(0);
-                Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
-                Destroy_Semaphore(vm->output_sem);
-                vm->output_sem=NULL;
-                if(!vm->online) {
-                	DBTRACE(0,"!USER HUNG UP");
-                	return(true);
-                }
-            }
-			ch=_clientAL;
-			RingBufWrite(&vm->out,&ch,1);
-#if 0	/* Now done in SBBS.DLL/XTRN.CPP */
-			if(ch==0xff) { /* escape TELNET IAC */
-				RingBufWrite(&vm->out,&ch,1);
-				DBTRACE(1,"Escaped IAC in output stream");
-			}
-#endif
-			vm->overrun=false;
-			_clientAX=PortStatus(vm);
-			break;
-		case 0x02: /* read char from com port */
-			if(!RingBufFull(&vm->in)) {
-            	DBTRACEx(0,"Waiting on input semaphore, hVM", hVM);
-            	vm->input_sem=Create_Semaphore(0);
-                Wait_Semaphore(vm->input_sem,BLOCK_THREAD_IDLE);
-                Destroy_Semaphore(vm->input_sem);
-                vm->input_sem=NULL;
-#if 0
-				_clientAH=0x80;	/* timed-out */
-				return(TRUE);
-#endif
-			}
-			RingBufRead(&vm->in,&ch,1);
-			_clientAH=0;
-			_clientAL=ch;
-			break;
-		case 0x03:	/* request status */
-			_clientAX=PortStatus(vm);
-			break;
-		case 0x04:	/* initialize */
-			DBTRACE(0,"Int14 func 4 init");
-			_clientAX=0x1954;	/* magic number = success */
-			_clientBH=5;		/* FOSSIL rev */
-			_clientBL=0x1B;		/* maximum FOSSIL func supported */
-			break;
-        case 0x08:	// flush output buffer
-            DBTRACE(0,"Int14 FLUSH OUTPUT BUFFER");
-            vm->output_sem=Create_Semaphore(0);
-            Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE);
-            Destroy_Semaphore(vm->output_sem);
-            vm->output_sem=NULL;
-			break;
-        case 0x09:	// purge output buffer
-        	DBTRACE(0,"Int14 PURGE OUTPUT BUFFER");
-        	RingBufReInit(&vm->out);
-            break;
-        case 0x0A:	// purge input buffer
-        	DBTRACE(0,"Int14 PURGE INPUT BUFFER");
-        	RingBufReInit(&vm->in);
-            break;
-		case 0x0B: /* write char to com port, no wait */
-        	if(RingBufFree(&vm->out)<2) {
-            	_clientAX=0; // char was not accepted
-                break;
-            }
-			ch=_clientAL;
-			RingBufWrite(&vm->out,&ch,1);
-#if 0	/* Now done in SBBS.DLL/XTRN.CPP */
-			if(ch==0xff) { /* escape TELNET IAC */
-				RingBufWrite(&vm->out,&ch,1);
-				DBTRACE(1,"Escaped IAC in output stream");
-			}
-#endif
-			_clientAX=1; // char was accepted
-			break;
-        case 0x0C:	// non-destructive read-ahead
-			if(!RingBufFull(&vm->in)) {
-				_clientAX=0xffff;	// no char available
-				break;
-			}
-			RingBufPeek(&vm->in,&ch,1);
-			_clientAH=0;
-			_clientAL=ch;
-			break;
-		case 0x13:	/* write to display */
-			dprintf("%c",_clientAL);
-			break;
-        case 0x18:	/* read bock */
-        	rd=_clientCX;
-            avail=RingBufFull(&vm->in);
-            if(rd>avail)
-            	rd=avail;
-            if(rd) {
-	            buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
-                rd = RingBufRead(&vm->in, buffer, rd);
-            }
-            _clientAX = rd;
-            break;
-        case 0x19:	/* write block */
-			wr=_clientCX;
-            avail=RingBufFree(&vm->out);
-            if(wr>avail)
-            	wr=avail;
-            if(wr) {
-	            buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
-                wr = RingBufWrite(&vm->out, buffer, wr);
-            }
-            _clientAX = wr;
-            break;
-#if 1
-        case 0x1B:	// driver info
-        {
-        	DBTRACE(1,"Int14 driver info");
-            struct {
-                WORD    info_size;
-                BYTE	curr_fossil;
-                BYTE	curr_rev;
-                DWORD	id_string;
-                WORD	inbuf_size;
-                WORD	inbuf_free;
-                WORD	outbuf_size;
-                WORD	outbuf_free;
-                BYTE	screen_width;
-                BYTE	screen_height;
-                BYTE	baud_rate;
-            } info={ sizeof(info), 5, 1, 0
-            		,RINGBUF_SIZE_IN-1, RingBufFree(&vm->in)
-                    ,RINGBUF_SIZE_OUT-1, RingBufFree(&vm->out)
-                    ,80,25
-                    ,1 // 38400
-                    };
-//			Map_Lin_To_VM_Addr
-			buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI);
-            wr=sizeof(info);
-            if(wr>_clientCX)
-            	wr=_clientCX;
-            memcpy(buffer, &info, wr);
-        	_clientAX=wr;
-            break;
-		}
-#endif
-		default:
-			DBTRACEx(0,"!UNHANDLED INTERRUPT 14h function",_clientAH);
-			break;
-	}
-	return(TRUE);	// Tells VMM that interrupt was handled
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SBBSExecInt10::SBBSExecInt10() : VPreChainV86Int(0x10)
-{
-	DBTRACE(0,"SBBSExecInt10 constructor");
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BOOL SBBSExecInt10::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno)
-{
-	BYTE 	ch;
-    DWORD   avail;
-	vm_t*	vm = find_vm(hVM);
-
-	if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) {
-		return(FALSE); // Tells VMM that interrupt was not handled
-	}
-
-	avail=RingBufFree(&vm->out);
-
- 	switch(_clientAH) {
-		case 0x02: // Set Cursor Position
-			DBTRACE(1,"Int10 func 2 - Set cursor position");
-			break;
-    	case 0x09:	// Write char and attr at cursor
-			DBTRACE(1,"Int10 func 9 - Write char and attr at curosr");
-        case 0x10:	// Write char at cursor
-#if 0
-			DBTRACE(1,"Int10 func 9 - Write char at curosr");			
-            if(!avail) {
-                DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM);
-                vm->overrun=true;
-				break;
-            }
-            ch=_clientAL;
-            RingBufWrite(&vm->out,&ch,1);
-            vm->overrun=false;
-			
-#endif
-			break;
-	}
-
-    return(FALSE);
-}
-
-
-
-DWORD SBBSExec::OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL)
-{
-	DWORD	rd;
-	DWORD	wr;
-	DWORD	avail;
-	vm_t*	vm;
-
-//	DBTRACEd(0,"SBBSEXEC ioctl"
-		//,pIOCTL->dioc_IOCtlCode);
-
-	switch(pIOCTL->dioc_IOCtlCode) {
-		case DIOC_OPEN:
-			DBTRACEd(0,"IOCTL: OPEN",Get_System_Time());
-			break;
-
-		case DIOC_CLOSEHANDLE:
-			DBTRACEd(0,"IOCTL: CLOSE",Get_System_Time());
-			break;
-
-		case SBBSEXEC_IOCTL_START:
-			DBTRACEd(0,"IOCTL: START",Get_System_Time());
-			DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle());
-			if(start.event) {
-				DBTRACE(0,"Exec already started!");
-				return(SBBSEXEC_ERROR_INUSE);
-			}
-			if (pIOCTL->dioc_InBuf==NULL 
-				|| pIOCTL->dioc_cbInBuf!=sizeof(start)) {
-				return(SBBSEXEC_ERROR_INBUF);
-			}
-			start=*(sbbsexec_start_t*)pIOCTL->dioc_InBuf;
-			break;
-
-		case SBBSEXEC_IOCTL_COMPLETE:
-			DBTRACEd(0,"IOCTL: COMPLETE",Get_System_Time());
-			if(start.event || new_vm==NULL) {
-				DBTRACE(0,"!VM never created");
-				start.event=0;
-				return(SBBSEXEC_ERROR_INUSE);
-			}
-			if(pIOCTL->dioc_OutBuf==NULL
-				|| pIOCTL->dioc_cbOutBuf<sizeof(VMHANDLE)) {
-				DBTRACE(0,"!Invalid OUTBUF");
-				return(SBBSEXEC_ERROR_OUTBUF);
-			}
-			*(VMHANDLE*)pIOCTL->dioc_OutBuf=new_vm->handle;
-			DBTRACEx(0,"CREATED VM HANDLE", new_vm->handle);
-			new_vm=NULL;
-
-			if(pIOCTL->dioc_bytesret!=NULL)
-				*pIOCTL->dioc_bytesret = sizeof(VMHANDLE);
-			break;
-		case SBBSEXEC_IOCTL_READ:
-
-			if (pIOCTL->dioc_InBuf==NULL
-				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
-				DBTRACE(0,"!INVALID INBUF");
-				return(SBBSEXEC_ERROR_INBUF);
-			}
-
-			if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf==0) {
-				DBTRACE(0,"!INVALID OUTBUF");
-				return(SBBSEXEC_ERROR_OUTBUF);
-			}
-
-			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
-			if(vm==NULL) {
-				DBTRACE(0,"!NO VM LIST");
-				return(SBBSEXEC_ERROR_INDATA);
-			}
-
-			rd = RingBufFull(&vm->out);
-
-			if(rd>pIOCTL->dioc_cbOutBuf) {
-				DBTRACEdd(0,"Reducing read size"
-                	,rd, pIOCTL->dioc_cbOutBuf);
-				rd=pIOCTL->dioc_cbOutBuf;
-			}
-
-			RingBufRead(&vm->out, (BYTE*)pIOCTL->dioc_OutBuf, rd);
-
-			if(pIOCTL->dioc_bytesret!=NULL)
-				*pIOCTL->dioc_bytesret = rd;
-
-            if(vm->output_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->output_sem);
-
-            if(rd>1) {
-            	DBTRACEd(1,"IOCTL_READ bytes", rd);
-            }
-			break;
-
-		case SBBSEXEC_IOCTL_WRITE:
-
-			if (pIOCTL->dioc_InBuf==NULL
-				|| pIOCTL->dioc_cbInBuf<sizeof(VMHANDLE)+1) {
-				DBTRACE(0,"!INVALID INBUF");
-				return(SBBSEXEC_ERROR_INBUF);
-			}
-
-			if (pIOCTL->dioc_OutBuf==NULL
-				|| pIOCTL->dioc_cbOutBuf!=sizeof(DWORD)) {
-				DBTRACE(0,"!INVALID OUTBUF");
-				return(SBBSEXEC_ERROR_OUTBUF);
-			}
-
-			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
-			if(vm==NULL) {
-				DBTRACE(0,"!NO VM LIST");
-				return(SBBSEXEC_ERROR_INDATA);
-			}
-
-			wr = pIOCTL->dioc_cbInBuf-sizeof(VMHANDLE);
-
-			avail = RingBufFree(&vm->in);
-
-			if(wr>avail) {
-				DBTRACEdd(0,"Reducing write size", wr, avail);
-				wr=avail;
-			}
-
-			RingBufWrite(&vm->in, (BYTE*)pIOCTL->dioc_InBuf+sizeof(VMHANDLE), wr);
-
-			*(DWORD *)pIOCTL->dioc_OutBuf = wr;
-
-			if(pIOCTL->dioc_bytesret!=NULL)
-				*pIOCTL->dioc_bytesret = sizeof(DWORD);
-
-            if(vm->input_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->input_sem);
-
-			// Wake up the VDM (improves keyboard response - dramatically!)
-			Wake_Up_VM(vm->handle);
-			break;
-
-		case SBBSEXEC_IOCTL_DISCONNECT:
-			DBTRACEd(0,"IOCTL: DISCONNECT",Get_System_Time());
-
-			if (pIOCTL->dioc_InBuf==NULL
-				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
-				DBTRACE(0,"!INVALID INBUF");
-				return(SBBSEXEC_ERROR_INBUF);
-			}
-
-			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
-			if(vm==NULL) {
-				DBTRACE(0,"!NO VM LIST");
-				return(SBBSEXEC_ERROR_INDATA);
-			}
-
-			vm->online=false;
-
-            if(vm->input_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->input_sem);
-            if(vm->output_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->output_sem);
-			break;
-
-		case SBBSEXEC_IOCTL_STOP:
-			DBTRACEd(0,"IOCTL: STOP",Get_System_Time());
-
-			if (pIOCTL->dioc_InBuf==NULL
-				|| pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) {
-				DBTRACE(0,"!INVALID INBUF");
-				return(SBBSEXEC_ERROR_INBUF);
-			}
-
-			vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf);
-			if(vm==NULL) {
-				DBTRACE(0,"!NO VM LIST");
-				return(SBBSEXEC_ERROR_INDATA);
-			}
-
-			DBTRACEx(0,"CLOSING VM HANDLE", vm->handle);
-			vm->handle=NULL;	// Mark as available
-			RingBufDispose(&vm->in);
-			RingBufDispose(&vm->out);
-            if(vm->input_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->input_sem);
-            if(vm->output_sem!=NULL) // Wake up int14 handler
-            	Signal_Semaphore(vm->output_sem);
-
-			vm->input_sem=NULL;
-			vm->output_sem=NULL;
-
-			break;
-
-		default:
-			DBTRACEdx(0,"!UNKNOWN IOCTL"
-				,pIOCTL->dioc_IOCtlCode,pIOCTL->dioc_IOCtlCode);
-			return(SBBSEXEC_ERROR_IOCTL);
-
-	}
-	return (0);	// DEVIOCTL_NOERROR);
-}
diff --git a/src/sbbs3/execvxd/sbbsexec.h b/src/sbbs3/execvxd/sbbsexec.h
deleted file mode 100644
index d6b5fea36f04facc669e396e47ab21122dbaf2e1..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/sbbsexec.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// sbbsexec.h - include file for SBBSEXEC
-
-/* Synchronet Windows 9X FOSSIL driver (requires VtoolsD C++ framework) */
-
-/* $Id: sbbsexec.h,v 1.2 2001/05/02 01:58:31 rswindell Exp $ */
-
-/****************************************************************************
- * @format.tab-size 4		(Plain Text/Source Code File Header)			*
- * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
- *																			*
- * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html		*
- *																			*
- * This program is free software; you can redistribute it and/or			*
- * modify it under the terms of the GNU General Public License				*
- * as published by the Free Software Foundation; either version 2			*
- * of the License, or (at your option) any later version.					*
- * See the GNU General Public License for more details: gpl.txt or			*
- * http://www.fsf.org/copyleft/gpl.html										*
- *																			*
- * Anonymous FTP access to the most recent released source is available at	*
- * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
- *																			*
- * Anonymous CVS access to the development source and modification history	*
- * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
- *     (just hit return, no password is necessary)							*
- * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
- *																			*
- * For Synchronet coding style and modification guidelines, see				*
- * http://www.synchro.net/source.html										*
- *																			*
- * You are encouraged to submit any modifications (preferably in Unix diff	*
- * format) via e-mail to mods@synchro.net									*
- *																			*
- * Note: If this box doesn't appear square, then you need to fix your tabs.	*
- ****************************************************************************/
-
-////////////////////////////////////////////////////////////////////////
-// Basic defintions for VToolsD framework
-
-#include <vtoolscp.h>
-#define DEVICE_CLASS		SBBSExec
-
-#define SBBSExec_DeviceID	UNDEFINED_DEVICE_ID
-#define SBBSExec_Major		1
-#define SBBSExec_Minor		1
-#define SBBSExec_Init_Order	UNDEFINED_INIT_ORDER
-
-#include "..\execvxd.h"		// sbbsexec_start_t definition
-#include "..\ringbuf.h"		// RingBuf/RingBuffer
-
-////////////////////////////////////////////////////////////////////////
-
-class SBBSExec : public VDevice
-{
-public:
-	virtual BOOL	OnDeviceInit(VMHANDLE hSysVM, PCHAR pszCmdTail);
-	virtual BOOL	OnSysDynamicDeviceInit();
-	virtual void	OnSystemExit(VMHANDLE hSysVM);
-	virtual BOOL	OnSysDynamicDeviceExit();
-	virtual BOOL	OnCreateVM(VMHANDLE hVM);
-	virtual DWORD	OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL);
-	void			UnhookInts(void);
-// Variables
-	class SBBSExecInt29*	pInt29;
-	class SBBSExecInt21*	pInt21;
-   	class SBBSExecInt16*	pInt16;
-	class SBBSExecInt14*	pInt14;
-	class SBBSExecInt10*	pInt10;
-};
-
-
-class SBBSExecInt29 : public VPreChainV86Int
-{
-public:
-	SBBSExecInt29();
-	virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
-};
-
-class SBBSExecInt21 : public VPreChainV86Int
-{
-public:
-	SBBSExecInt21();
-	virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
-};
-
-class SBBSExecInt16 : public VPreChainV86Int
-{
-public:
-	SBBSExecInt16();
-	virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
-};
-
-class SBBSExecInt14 : public VPreChainV86Int
-{
-public:
-	SBBSExecInt14();
-	virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
-};
-
-class SBBSExecInt10 : public VPreChainV86Int
-{
-public:
-	SBBSExecInt10();
-	virtual BOOL handler(VMHANDLE, CLIENT_STRUCT*, DWORD);
-};
diff --git a/src/sbbs3/execvxd/sbbsexec.vrc b/src/sbbs3/execvxd/sbbsexec.vrc
deleted file mode 100644
index 98781a24f80ec01e6240e4df15e26a3bc18ac3e4..0000000000000000000000000000000000000000
--- a/src/sbbs3/execvxd/sbbsexec.vrc
+++ /dev/null
@@ -1,9 +0,0 @@
-CompanyName	=	"Company Name" 
-FileDescription =	"VxD File Description"
-FileVersion	=	"Version 1.00" 
-InternalName	=	"DEVNAME"
-LegalCopyright	= 	"Copyright \251 1995, Company Name. "
-OriginalFilename = 	"device.vxd"
-ProductName	=	"Product Name"
-ProductVersion	= 	"Version 1.00"
-Translation	=	0x409, 0x4E4
diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index 4879fe1fdd732deb12938b8bfac2b92cc43cc6dd..2628ea1bc0aeacb4e3fbfa9327d611539c6a781e 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -395,12 +395,10 @@ typedef enum {						/* Values for xtrn_t.event				*/
 #define SAVECOLUMNS		(1<<22)		/* Save/share current terminal width	*/
 #define XTRN_UTF8		(1<<23)		/* External program supports UTF-8		*/
 #define XTRN_TEMP_DIR	(1<<24)		/* Place drop files in temp dir			*/
-#define XTRN_UART		(1<<25)		/* Disable the int14h/FOSSIL driver		*/
+#define XTRN_UART		(1<<25)		/* Enable the virtual UART driver		*/
+#define XTRN_FOSSIL		(1<<26)		/* Enable the int14h/FOSSIL driver		*/
 #define XTRN_CONIO		(1<<31)		/* Intercept Windows Console I/O (Drwy)	*/
 
-									/* Bits in cfg.xtrn_misc				*/
-#define XTRN_NO_MUTEX	(1<<0)		/* Do not use exec_mutex for FOSSIL VXD	*/
-
 									/* Bits in user.qwk 					*/
 #define QWK_FILES	(1L<<0) 		/* Include new files list				*/
 #define QWK_EMAIL	(1L<<1) 		/* Include unread e-mail				*/
@@ -812,6 +810,7 @@ enum {							/* readmail and delmailidx which types		*/
 #define EX_NOECHO	XTRN_NOECHO		/* Don't echo stdin to stdout 			*/
 #define EX_STDIO	(EX_STDIN|EX_STDOUT)
 #define EX_UART		XTRN_UART
+#define EX_FOSSIL	XTRN_FOSSIL
 #define EX_NOLOG	(1<<30)		/* Don't log intercepted stdio				*/
 #define EX_CONIO	(1<<31)		/* Intercept Windows console I/O (doorway)	*/
 #define EX_UNSPECIFIED	-1
diff --git a/src/sbbs3/sbbsexec.c b/src/sbbs3/sbbsexec.c
index 5d95788e741f3c16f74acac12816d0e22e1e9bad..e09f15fbb040f77c0bff9b37e763bb1f33979ef4 100644
--- a/src/sbbs3/sbbsexec.c
+++ b/src/sbbs3/sbbsexec.c
@@ -68,7 +68,7 @@ BYTE uart_divisor_latch_msb		= 0x00;
 	int log_level = LOG_WARNING;
 #endif
 
-BOOL		virtualize_uart=TRUE;
+BOOL		virtualize_uart=FALSE;
 double		yield_interval=1.0;
 BOOL		hangup_supported=TRUE;
 HANDLE		hangup_event=NULL;
@@ -799,6 +799,10 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
 			hangup();
 			break;
 
+		case VDD_VIRTUALIZE_UART:
+			virtualize_uart = TRUE;
+			break;
+
 		default:
 			lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL());
 			break;
diff --git a/src/sbbs3/scfg/scfgxtrn.c b/src/sbbs3/scfg/scfgxtrn.c
index a26b90f183ef1dc9326e5097cbaedb07b265715d..dc189928b78e2285f0a7e4699655850ed60c808c 100644
--- a/src/sbbs3/scfg/scfgxtrn.c
+++ b/src/sbbs3/scfg/scfgxtrn.c
@@ -880,9 +880,9 @@ const char* io_method(uint32_t mode)
 	static char str[128];
 
 	sprintf(str,"%s%s%s"
-		,mode & XTRN_UART ? "UART"
-			: (mode & XTRN_STDIO ? "Standard"
-				: mode & XTRN_CONIO ? "Console": (mode & XTRN_NATIVE ? "Socket" : "FOSSIL or UART"))
+		,mode & XTRN_UART ? "UART" : (mode & XTRN_FOSSIL) ? "FOSSIL"
+				: (mode & XTRN_STDIO ? "Standard"
+					: mode & XTRN_CONIO ? "Console": (mode & XTRN_NATIVE ? "Socket" : "FOSSIL or UART"))
 		,(mode & (XTRN_STDIO|WWIVCOLOR)) == (XTRN_STDIO|WWIVCOLOR) ? ", WWIV Color" : ""
 		,(mode & (XTRN_STDIO|XTRN_NOECHO)) == (XTRN_STDIO|XTRN_NOECHO) ? ", No Echo" : "");
 	return str;
@@ -892,13 +892,16 @@ void choose_io_method(uint32_t* misc)
 {
 	int k;
 
-	switch((*misc) & (XTRN_STDIO|XTRN_UART)) {
+	switch((*misc) & (XTRN_STDIO|XTRN_UART|XTRN_FOSSIL)) {
 		case XTRN_STDIO:
 			k=0;
 			break;
 		case XTRN_UART:
 			k=2;
 			break;
+		case XTRN_FOSSIL:
+			k=3;
+			break;
 		default:
 			k=1;
 			break;
@@ -952,15 +955,16 @@ void choose_io_method(uint32_t* misc)
 			"   This setting is not applied when invoking Baja or JavaScript modules.\n"
 		;
 		strcpy(opt[1], "FOSSIL or UART");
-		strcpy(opt[2], "UART");
-		opt[3][0] = '\0';
+		strcpy(opt[2], "UART Only");
+		strcpy(opt[3], "FOSSIL Only");
+		opt[4][0] = '\0';
 	}
 	switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"I/O Method"
 		,opt)) {
 		case 0: /* Standard I/O */
-			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != XTRN_STDIO) {
+			if(((*misc) & (XTRN_STDIO|XTRN_UART|XTRN_FOSSIL)) != XTRN_STDIO) {
 				(*misc) |=XTRN_STDIO;
-				(*misc) &=~XTRN_UART;
+				(*misc) &=~XTRN_UART|XTRN_FOSSIL;
 				uifc.changes = TRUE;
 			}
 			k=((*misc) & WWIVCOLOR) ? 0:1;
@@ -999,16 +1003,23 @@ void choose_io_method(uint32_t* misc)
 				uifc.changes=TRUE; 
 			}
 			break;
-		case 1:	/* FOSSIL or Socket */
-			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != 0) {
-				(*misc) &= ~(XTRN_UART|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
+		case 1:	/* FOSSIL or UART or Socket */
+			if(((*misc) & (XTRN_STDIO|XTRN_UART|XTRN_FOSSIL)) != 0) {
+				(*misc) &= ~(XTRN_UART|XTRN_FOSSIL|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
 				uifc.changes=TRUE; 
 			}
 			break;
 		case 2: /* UART */
-			if(((*misc) & (XTRN_STDIO|XTRN_UART)) != XTRN_UART) {
+			if(((*misc) & (XTRN_STDIO|XTRN_UART|XTRN_FOSSIL)) != XTRN_UART) {
 				(*misc) |= XTRN_UART;
-				(*misc) &= ~(XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
+				(*misc) &= ~(XTRN_FOSSIL|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
+				uifc.changes=TRUE; 
+			}
+			break;
+		case 3: /* FOSSIL */
+			if(((*misc) & (XTRN_STDIO|XTRN_UART|XTRN_FOSSIL)) != XTRN_FOSSIL) {
+				(*misc) |= XTRN_FOSSIL;
+				(*misc) &= ~(XTRN_UART|XTRN_STDIO|WWIVCOLOR|XTRN_NOECHO);
 				uifc.changes=TRUE; 
 			}
 			break;
diff --git a/src/sbbs3/vdd_func.h b/src/sbbs3/vdd_func.h
index 1e66f1117ce73b45ddc9b5d8f9665fac27f230c7..0c42abf0ca3e66d10ab0891685626d6095df9c37 100644
--- a/src/sbbs3/vdd_func.h
+++ b/src/sbbs3/vdd_func.h
@@ -1,9 +1,5 @@
-/* VDD_FUNC.H */
-
 /* Synchronet WinNT VDD FOSSIL constant/type definitions */
 
-/* $Id: vdd_func.h,v 1.10 2018/07/24 01:11:08 rswindell Exp $ */
-
 /****************************************************************************
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
@@ -56,6 +52,7 @@ enum {
 	,VDD_LOAD_INI_SECTION	=16
 	,VDD_DEBUG_OUTPUT		=17
 	,VDD_HANGUP				=18
+	,VDD_VIRTUALIZE_UART	=19
 };
 
 typedef struct {
@@ -65,3 +62,10 @@ typedef struct {
 	DWORD outbuf_size;
 	DWORD outbuf_full;
 } vdd_status_t;
+
+#define SBBSEXEC_MODE_UNSPECIFIED	0
+#define SBBSEXEC_MODE_DOS_IN		(1<<0)
+#define SBBSEXEC_MODE_DOS_OUT		(1<<1)
+#define SBBSEXEC_MODE_UART			(1<<2)
+#define SBBSEXEC_MODE_FOSSIL		(1<<3)
+#define SBBSEXEC_MODE_DEFAULT		(SBBSEXEC_MODE_UART | SBBSEXEC_MODE_FOSSIL)
diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp
index 00e196ff84ee822015b0586daf8fead771e0218a..228ebea764cc0dcdda23cbbaa7bbd046cab757db 100644
--- a/src/sbbs3/xtrn.cpp
+++ b/src/sbbs3/xtrn.cpp
@@ -261,7 +261,7 @@ static bool native_executable(scfg_t* cfg, const char* cmdline, long mode)
 
 #ifdef _WIN32
 
-#include "execvxd.h"	/* DOSXTRN.EXE API */
+#include "vdd_func.h"	/* DOSXTRN.EXE API */
 
 extern SOCKET node_socket[];
 
@@ -292,7 +292,6 @@ static void add_env_var(str_list_t* list, const char* var, const char* val)
 /* Clean-up resources while preserving current LastError value */
 #define XTRN_CLEANUP												\
 	last_error=GetLastError();										\
-    if(vxd!=INVALID_HANDLE_VALUE)		CloseHandle(vxd);			\
 	if(rdslot!=INVALID_HANDLE_VALUE)	CloseHandle(rdslot);		\
 	if(wrslot!=INVALID_HANDLE_VALUE)	CloseHandle(wrslot);		\
 	if(start_event!=NULL)				CloseHandle(start_event);	\
@@ -327,7 +326,6 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 	BOOL	processTerminated=false;
 	uint	i;
     time_t	hungup=0;
-	HANDLE	vxd=INVALID_HANDLE_VALUE;
 	HANDLE	rdslot=INVALID_HANDLE_VALUE;
 	HANDLE	wrslot=INVALID_HANDLE_VALUE;
 	HANDLE  start_event=NULL;
@@ -478,15 +476,15 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
         SAFEPRINTF2(fullcmdline, "%sDOSXTRN.EXE %s", cfg.exec_dir, path);
 
 		if(!(mode&EX_OFFLINE)) {
+			i = SBBSEXEC_MODE_UNSPECIFIED;
 			if(mode & EX_UART)
-				i=SBBSEXEC_MODE_UART;
-			else {
-				i=SBBSEXEC_MODE_FOSSIL;
-				if(mode&EX_STDIN)
-           			i|=SBBSEXEC_MODE_DOS_IN;
-				if(mode&EX_STDOUT)
-        			i|=SBBSEXEC_MODE_DOS_OUT;
-			}
+				i |= SBBSEXEC_MODE_UART;
+			if(mode & EX_FOSSIL)
+				i |= SBBSEXEC_MODE_FOSSIL;
+			if(mode & EX_STDIN)
+           		i |= SBBSEXEC_MODE_DOS_IN;
+			if(mode & EX_STDOUT)
+        		i |= SBBSEXEC_MODE_DOS_OUT;
 			BOOL x64 = FALSE;
 			IsWow64Process(GetCurrentProcess(), &x64);
 			sprintf(str," %s %u %u"
@@ -646,7 +644,7 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
     while(!(mode&EX_BG)) {
 		if(mode&EX_CHKTIME)
 			gettimeleft();
-        if(!online && !(mode&EX_OFFLINE)) { // Tell VXD/VDD and external that user hung-up
+        if(!online && !(mode&EX_OFFLINE)) { // Tell VDD and external that user hung-up
         	if(was_online) {
 				logline(LOG_NOTICE,"X!","hung-up in external program");
             	hungup=time(NULL);
diff --git a/src/sbbs3/xtrn_sec.cpp b/src/sbbs3/xtrn_sec.cpp
index 2f385b5c403f4e40efd876ccc94370c73c6ef8e0..18d4ba887c17f94244496896123cadbc7b29213f 100644
--- a/src/sbbs3/xtrn_sec.cpp
+++ b/src/sbbs3/xtrn_sec.cpp
@@ -1587,6 +1587,8 @@ bool sbbs_t::exec_xtrn(uint xtrnnum)
 		mode|=EX_CONIO;
 	else if(cfg.xtrn[xtrnnum]->misc&XTRN_UART)
 		mode|=EX_UART;
+	else if(cfg.xtrn[xtrnnum]->misc&XTRN_FOSSIL)
+		mode|=EX_FOSSIL;
 	mode|=(cfg.xtrn[xtrnnum]->misc&(XTRN_CHKTIME|XTRN_NATIVE|XTRN_NOECHO|WWIVCOLOR));
 	if(cfg.xtrn[xtrnnum]->misc&MODUSERDAT) {		/* Delete MODUSER.DAT */
 		SAFEPRINTF(str,"%sMODUSER.DAT",dropdir);	/* if for some weird  */