diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 41a1836da..1165f3c5d 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,13 @@
+June 23, 2006
+- Changed the archive format for crash reports from tar.gz to zip.
+- Went back to a single process model for crash reporting. It appears there
+  are some machines that don't like having another process collect the
+  information and report it. I still feel that having another process do
+  it _should_ be more reliable, because that process can execute in a known
+  good state. Ah well. I haven't yet seen anything that left the main process
+  in a totally unrecoverable state, so it's probably okay. Unlike before, this
+  single-process version is still GCC-compatible.
+
 June 22, 2006 (Changes by Graf Zahl)
 - Fixed: The resurrect cheat didn't reset the player's damage type so
   if he died by being frozen the blue blend didn't disappear.
diff --git a/src/win32/gccseh.h b/src/win32/gccseh.h
deleted file mode 100644
index 9813e2658..000000000
--- a/src/win32/gccseh.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// GCC does not support Windows' Structured Exception Handling. :-(
-// So I have to fake it using inline assembly
-
-#ifdef __GNUC__
-
-#define __try try
-#define __except(a)	catch(...)
-
-#define EH_NONCONTINUABLE       0x01
-#define EH_UNWINDING            0x02
-#define EH_EXIT_UNWIND          0x04
-#define EH_STACK_INVALID        0x08
-#define EH_NESTED_CALL          0x10
-
-typedef enum {
-	ExceptionContinueExecution,
-	ExceptionContinueSearch,
-	ExceptionNestedException,
-	ExceptionCollidedUnwind
-} EXCEPTION_DISPOSITION;
-
-typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)
-            (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
-
-typedef struct _EXCEPTION_REGISTRATION
-{
-	struct _EXCEPTION_REGISTRATION* Prev;
-	PEXCEPTION_HANDLER              Handler;
-} EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION;
-
-#endif
diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp
index a8cdbea17..071e9edb1 100644
--- a/src/win32/i_crash.cpp
+++ b/src/win32/i_crash.cpp
@@ -32,6 +32,8 @@
 **
 */
 
+// HEADER FILES ------------------------------------------------------------
+
 #define WIN32_LEAN_AND_MEAN
 #define _WIN32_WINNT 0x0501
 #include <windows.h>
@@ -51,6 +53,7 @@
 #include <stddef.h>
 #include "resource.h"
 #include "version.h"
+#include "m_swap.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -58,16 +61,7 @@
 #include <time.h>
 #include <zlib.h>
 
-// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
-// giving them proper prototypes under Win32, they are just macros for
-// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs.
-#ifdef _WIN64
-typedef LONG_PTR WLONG_PTR;
-#else
-typedef LONG WLONG_PTR;
-#endif
-
-HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
+// MACROS ------------------------------------------------------------------
 
 #define BUGS_FORUM_URL	"http://forum.zdoom.org/index.php?c=3"
 
@@ -80,11 +74,143 @@ HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
 // If you are working on your own modified version of ZDoom, change
 // the last part of the UPLOAD_AGENT (between parentheses) to your
 // own program's name. e.g. (Skulltag) or (ZDaemon) or (ZDoomFu)
-#define UPLOAD_AGENT	"ZDoom/" DOTVERSIONSTR " (ZDoom the Original)"
+#define UPLOAD_AGENT	"ZDoom/" DOTVERSIONSTR " (" GAMESIG ")"
 
 // Time, in milliseconds, to wait for a send() or recv() to complete.
 #define TIMEOUT			60000
 
+// Maximum number of files that might appear in a crash report.
+#define MAX_FILES 5
+
+#ifndef WORDS_BIGENDIAN
+#define MAKE_ID(a,b,c,d)	((a)|((b)<<8)|((c)<<16)|((d)<<24))
+#else
+#define MAKE_ID(a,b,c,d)	((d)|((c)<<8)|((b)<<16)|((a)<<24))
+#endif
+
+#define ZIP_LOCALFILE	MAKE_ID('P','K',3,4)
+#define ZIP_CENTRALFILE	MAKE_ID('P','K',1,2)
+#define ZIP_ENDOFDIR	MAKE_ID('P','K',5,6)
+
+// TYPES -------------------------------------------------------------------
+
+// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
+// giving them proper prototypes under Win32, they are just macros for
+// Get/SetWindowLong, meaning they take LONGs and not LONG_PTRs.
+#ifdef _WIN64
+typedef LONG_PTR WLONG_PTR;
+#else
+typedef LONG WLONG_PTR;
+#endif
+
+namespace zip
+{
+#pragma pack(push,1)
+	struct LocalFileHeader
+	{
+		DWORD	Magic;						// 0
+		BYTE	VersionToExtract[2];		// 4
+		WORD	Flags;						// 6
+		WORD	Method;						// 8
+		WORD	ModTime;					// 10
+		WORD	ModDate;					// 12
+		DWORD	CRC32;						// 14
+		DWORD	CompressedSize;				// 18
+		DWORD	UncompressedSize;			// 22
+		WORD	NameLength;					// 26
+		WORD	ExtraLength;				// 28
+	};
+
+	struct CentralDirectoryEntry
+	{
+		DWORD	Magic;
+		BYTE	VersionMadeBy[2];
+		BYTE	VersionToExtract[2];
+		WORD	Flags;
+		WORD	Method;
+		WORD	ModTime;
+		WORD	ModDate;
+		DWORD	CRC32;
+		DWORD	CompressedSize;
+		DWORD	UncompressedSize;
+		WORD	NameLength;
+		WORD	ExtraLength;
+		WORD	CommentLength;
+		WORD	StartingDiskNumber;
+		WORD	InternalAttributes;
+		DWORD	ExternalAttributes;
+		DWORD	LocalHeaderOffset;
+	};
+
+	struct EndOfCentralDirectory
+	{
+		DWORD	Magic;
+		WORD	DiskNumber;
+		WORD	FirstDisk;
+		WORD	NumEntries;
+		WORD	NumEntriesOnAllDisks;
+		DWORD	DirectorySize;
+		DWORD	DirectoryOffset;
+		WORD	ZipCommentLength;
+	};
+#pragma pack(pop)
+}
+
+struct TarFile
+{
+	HANDLE		File;
+	const char *Filename;
+	int			ZipOffset;
+	DWORD		UncompressedSize;
+	DWORD		CompressedSize;
+	DWORD		CRC32;
+	bool		Deflated;
+};
+
+typedef BOOL (WINAPI *THREADWALK) (HANDLE, LPTHREADENTRY32);
+typedef BOOL (WINAPI *MODULEWALK) (HANDLE, LPMODULEENTRY32);
+typedef HANDLE (WINAPI *CREATESNAPSHOT) (DWORD, DWORD);
+typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
+								  PMINIDUMP_EXCEPTION_INFORMATION,
+								  PMINIDUMP_USER_STREAM_INFORMATION,
+								  PMINIDUMP_CALLBACK_INFORMATION);
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static void AddFile (HANDLE file, const char *filename);
+static void CloseTarFiles ();
+static HANDLE MakeZip ();
+static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, short dostime);
+static HANDLE CreateTempFile ();
+
+static void DumpBytes (HANDLE file, BYTE *address);
+static void AddStackInfo (HANDLE file, void *dumpaddress);
+static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack);
+static void AddToolHelp (HANDLE file);
+
+static HANDLE WriteTextReport ();
+
+static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+static void SetEditControl (HWND control, HWND sizedisplay, int filenum);
+
+static BOOL UploadReport (HANDLE report, bool gziped);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+extern HINSTANCE g_hInst;
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+EXCEPTION_POINTERS CrashPointers;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static HRESULT (__stdcall *pEnableThemeDialogTexture) (HWND hwnd, DWORD dwFlags);
+
 static const char PostHeader[] =
 "POST " UPLOAD_URI " HTTP/1.1\r\n"
 "Host: " REMOTE_HOST "\r\n"
@@ -132,70 +258,10 @@ static const char DbgHelpRequest[] =
 "User-Agent: " UPLOAD_AGENT "\r\n"
 "\r\n";
 
-
-namespace tar
-{
-	/*
-	* Standard Archive Format - Standard TAR - USTAR
-	*/
-	enum
-	{
-		RECORDSIZE =	512,
-		NAMSIZE	=		100,
-		TUNMLEN =		32,
-		TGNMLEN =		32
-	};
-
-	union record {
-		unsigned char charptr[RECORDSIZE];
-		struct {
-			char	name[NAMSIZE];
-			char	mode[8];
-			char	uid[8];
-			char	gid[8];
-			char	size[12];
-			char	mtime[12];
-			char	chksum[8];
-			char	linkflag;
-			char	linkname[NAMSIZE];
-			char	magic[8];
-			char	uname[TUNMLEN];
-			char	gname[TGNMLEN];
-			char	devmajor[8];
-			char	devminor[8];
-		} header;
-	};
-}
-
-#define MAX_FILES 5
-
-struct TarFile
-{
-	HANDLE File;
-	const char *Filename;
-};
 static TarFile TarFiles[MAX_FILES];
+
 static int NumFiles;
 
-static void AddFile (HANDLE file, const char *filename);
-static void CloseTarFiles ();
-static HANDLE MakeTar (bool &gzip);
-static HANDLE CreateTempFile ();
-
-typedef BOOL (WINAPI *THREADWALK) (HANDLE, LPTHREADENTRY32);
-typedef BOOL (WINAPI *MODULEWALK) (HANDLE, LPMODULEENTRY32);
-typedef HANDLE (WINAPI *CREATESNAPSHOT) (DWORD, DWORD);
-typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
-								  PMINIDUMP_EXCEPTION_INFORMATION,
-								  PMINIDUMP_USER_STREAM_INFORMATION,
-								  PMINIDUMP_CALLBACK_INFORMATION);
-
-extern HINSTANCE g_hInst;
-
-EXCEPTION_POINTERS CrashPointers;
-EXCEPTION_RECORD MyExceptionRecord;
-CONTEXT MyContextRecord;
-
 static HANDLE DbgProcess;
 static DWORD DbgProcessID;
 static DWORD DbgThreadID;
@@ -204,17 +270,48 @@ static PVOID CrashAddress;
 static bool NeedDbgHelp;
 static char CrashSummary[256];
 
-static void DumpBytes (HANDLE file, BYTE *address);
-static void AddStackInfo (HANDLE file, void *dumpaddress);
-static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack);
-static void AddToolHelp (HANDLE file);
+static WNDPROC StdStaticProc;
 
-static HANDLE WriteTextReport ();
+// CODE --------------------------------------------------------------------
 
-static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
-static void SetEditControl (HWND control, HWND sizedisplay, int filenum);
+//==========================================================================
+//
+// SafeReadMemory
+//
+// Returns true if the memory was succussfully read and false if not.
+//
+//==========================================================================
 
-static BOOL UploadReport (HANDLE report, bool gziped);
+static bool SafeReadMemory (const void *base, void *buffer, size_t len)
+{
+	// Non-GCC version: Use SEH to catch any bad reads immediately when
+	// they happen instead of trying to catch them beforehand.
+	//
+	// GCC version: Test the memory beforehand and hope it doesn't become
+	// unreadable while we read it. GCC is the only Windows compiler (that
+	// I know of) that can't do SEH.
+#ifdef __GNUC__
+	if (IsBadReadPtr (base, len) != 0)
+	{
+		return false;
+	}
+#endif
+	bool success = false;
+
+#ifndef __GNUC__
+	__try
+	{
+#endif
+		memcpy (buffer, base, len);
+		success = true;
+#ifndef __GNUC__
+	}
+	__except(EXCEPTION_EXECUTE_HANDLER)
+	{
+	}
+#endif
+	return success;
+}
 
 //==========================================================================
 //
@@ -321,7 +418,7 @@ void __cdecl Writef (HANDLE file, const char *format, ...)
 //
 //==========================================================================
 
-void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTION_POINTERS exceptionRecord, char *custominfo, DWORD customsize)
+void CreateCrashLog (char *custominfo, DWORD customsize)
 {
 	// Do not collect information more than once.
 	if (NumFiles != 0)
@@ -329,59 +426,46 @@ void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTIO
 		return;
 	}
 
-	DbgThreadID = threadID;
-	DbgProcessID = processID;
-	DbgProcess = process;
-	if (!ReadProcessMemory (DbgProcess, exceptionRecord, &CrashPointers, sizeof(CrashPointers), NULL) ||
-		!ReadProcessMemory (DbgProcess, CrashPointers.ExceptionRecord, &MyExceptionRecord, sizeof(EXCEPTION_RECORD), NULL) ||
-		!ReadProcessMemory (DbgProcess, CrashPointers.ContextRecord, &MyContextRecord, sizeof(CONTEXT), NULL))
+	DbgThreadID = GetCurrentThreadId();
+	DbgProcessID = GetCurrentProcessId();
+	DbgProcess = GetCurrentProcess();
+
+	CrashCode = CrashPointers.ExceptionRecord->ExceptionCode;
+	CrashAddress = CrashPointers.ExceptionRecord->ExceptionAddress;
+
+	AddFile (WriteTextReport(), "report.txt");
+	AddFile (WriteMyMiniDump(), "minidump.mdmp");
+
+	// Copy app-specific information out of the crashing process's memory
+	// and into a new temporary file.
+	if (customsize != 0)
 	{
 		HANDLE file = CreateTempFile();
+		DWORD wrote;
 
-		Writef (file, "Could not read process memory\n");
-		AddFile (file, "failed.txt");
-	}
-	else
-	{
-		CrashPointers.ExceptionRecord = &MyExceptionRecord;
-		CrashPointers.ContextRecord = &MyContextRecord;
-		CrashCode = CrashPointers.ExceptionRecord->ExceptionCode;
-		CrashAddress = CrashPointers.ExceptionRecord->ExceptionAddress;
-
-		AddFile (WriteTextReport(), "report.txt");
-		AddFile (WriteMyMiniDump(), "minidump.mdmp");
-
-		// Copy app-specific information out of the crashing process's memory
-		// and into a new temporary file.
-		if (customsize != 0)
+		if (file != INVALID_HANDLE_VALUE)
 		{
-			HANDLE file = CreateTempFile();
-			DWORD wrote;
+			BYTE buffer[512];
+			DWORD left;
 
-			if (file != INVALID_HANDLE_VALUE)
+			for (;; customsize -= left, custominfo += left)
 			{
-				BYTE buffer[512];
-				DWORD left;
-
-				for (;; customsize -= left, custominfo += left)
+				left = customsize > 512 ? 512 : customsize;
+				if (left == 0)
 				{
-					left = customsize > 512 ? 512 : customsize;
-					if (left == 0)
-					{
-						break;
-					}
-					if (ReadProcessMemory (DbgProcess, custominfo, buffer, left, NULL))
-					{
-						WriteFile (file, buffer, left, &wrote, NULL);
-					}
-					else
-					{
-						Writef (file, "Failed reading remaining %lu bytes\r\n", customsize);
-						break;
-					}
+					break;
+				}
+				if (SafeReadMemory (custominfo, buffer, left))
+				{
+					WriteFile (file, buffer, left, &wrote, NULL);
+				}
+				else
+				{
+					Writef (file, "Failed reading remaining %lu bytes\r\n", customsize);
+					break;
 				}
-				AddFile (file, "local.txt");
 			}
+			AddFile (file, "local.txt");
 		}
 	}
 	CloseHandle (DbgProcess);
@@ -675,7 +759,7 @@ static void AddStackInfo (HANDLE file, void *dumpaddress)
 		Writef (file, "%p:", scan);
 		for (i = 0; i < max; ++i)
 		{
-			if (!ReadProcessMemory (DbgProcess, &scan[i], &peekd, 4, NULL))
+			if (!SafeReadMemory (&scan[i], &peekd, 4))
 			{
 				break;
 			}
@@ -688,7 +772,7 @@ static void AddStackInfo (HANDLE file, void *dumpaddress)
 		Writef (file, "  ");
 		for (i = 0; i < max*4; ++i)
 		{
-			if (!ReadProcessMemory (DbgProcess, (BYTE *)scan + i, &peekb, 1, NULL))
+			if (!SafeReadMemory ((BYTE *)scan + i, &peekb, 1))
 			{
 				break;
 			}
@@ -725,7 +809,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
 	{
 		DWORD_PTR code;
 
-		if (ReadProcessMemory (DbgProcess, scan, &code, sizeof(code), NULL) &&
+		if (SafeReadMemory (scan, &code, sizeof(code)) &&
 			code >= codeStart && code < codeEnd)
 		{
 			static const char regNames[][4] =
@@ -737,18 +821,18 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
 			const BYTE *bytep = (BYTE *)code;
 			BYTE peekb;
 
-#define chkbyte(x,m,v) ReadProcessMemory(DbgProcess, x, &peekb, 1, NULL) && ((peekb & m) == v)
+#define chkbyte(x,m,v) SafeReadMemory(x, &peekb, 1) && ((peekb & m) == v)
 
 			if (chkbyte(bytep - 5, 0xFF, 0xE8) || chkbyte(bytep - 5, 0xFF, 0xE9))
 			{
 				DWORD peekd;
-				if (ReadProcessMemory (DbgProcess, bytep - 4, &peekd, 4, NULL))
+				if (SafeReadMemory (bytep - 4, &peekd, 4))
 				{
 					DWORD_PTR jumpaddr = peekd + code;
 					Writef (file, "\r\n %p  %s %p", code - 5,
 						peekb == 0xE9 ? "jmp " : "call", jumpaddr);
 					if (chkbyte((LPCVOID)jumpaddr, 0xFF, 0xE9) &&
-						ReadProcessMemory (DbgProcess, (LPCVOID)(jumpaddr + 1), &peekd, 4, NULL))
+						SafeReadMemory ((LPCVOID)(jumpaddr + 1), &peekd, 4))
 					{
 						Writef (file," => jmp  %p", peekd + jumpaddr + 5);
 					}
@@ -785,7 +869,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
 
 					Writef (file, "\r\n %08x", bytep - i);
 					bytep -= i - 1;
-					ReadProcessMemory (DbgProcess, bytep, &peekb, 1, NULL);
+					SafeReadMemory (bytep, &peekb, 1);
 					mod = peekb >> 6;
 					rm = peekb & 7;
 					bytep++;
@@ -798,7 +882,7 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
 					{
 						int index, base;
 
-						ReadProcessMemory (DbgProcess, bytep, &peekb, 1, NULL);
+						SafeReadMemory (bytep, &peekb, 1);
 						scale = 1 << (peekb >> 6);
 						index = (peekb >> 3) & 7;
 						base = peekb & 7;
@@ -832,12 +916,12 @@ static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack)
 					if (mod == 1)
 					{
 						signed char miniofs;
-						ReadProcessMemory (DbgProcess, bytep++, &miniofs, 1, NULL);
+						SafeReadMemory (bytep++, &miniofs, 1);
 						offset = miniofs;
 					}
 					else
 					{
-						ReadProcessMemory (DbgProcess, bytep, &offset, 4, NULL);
+						SafeReadMemory (bytep, &offset, 4);
 						bytep += 4;
 					}
 					if ((DWORD_PTR)bytep == code)
@@ -905,7 +989,7 @@ static void DumpBytes (HANDLE file, BYTE *address)
 		{
 			line_p += sprintf (line_p, "\r\n%p:", address);
 		}
-		if (ReadProcessMemory (DbgProcess, address, &peek, 1, NULL))
+		if (SafeReadMemory (address, &peek, 1))
 		{
 			line_p += sprintf (line_p, " %02x", *address);
 		}
@@ -989,40 +1073,44 @@ static void CloseTarFiles ()
 // WriteBlock
 //
 // This is a wrapper around WriteFile. If stream is non-NULL, then the data
-// is compressed before writing it to the file. outbuf must be 512 bytes.
+// is compressed before writing it to the file. outbuf must be 1024 bytes.
 //
 //==========================================================================
 
-static void WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stream, Bytef *outbuf, DWORD *crc)
+static DWORD WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stream, Bytef *outbuf)
 {
 	if (stream == NULL)
 	{
 		WriteFile (file, buffer, bytes, &bytes, NULL);
+		return bytes;
 	}
 	else
 	{
+		DWORD wrote = 0;
+
 		stream->next_in = (Bytef *)buffer;
 		stream->avail_in = bytes;
-		*crc = crc32 (*crc, (const Bytef *)buffer, bytes);
 
 		while (stream->avail_in != 0)
 		{
 			if (stream->avail_out == 0)
 			{
 				stream->next_out = outbuf;
-				stream->avail_out = sizeof(tar::record);
-				WriteFile (file, outbuf, sizeof(tar::record), &bytes, NULL);
+				stream->avail_out = 1024;
+				wrote += 1024;
+				WriteFile (file, outbuf, 1024, &bytes, NULL);
 			}
 			deflate (stream, Z_NO_FLUSH);
 		}
+		return wrote;
 	}
 }
 
 //==========================================================================
 //
-// WriteTar
+// WriteZip
 //
-// Writes a .tar.gz file. If deflateInit fails, then ".gz" the gzip
+// Writes a .zip/pk3 file. If deflateInit fails, then ".gz" the gzip
 // argument will be false, otherwise it will be set true. A HANDLE to the
 // file is returned. This file is delete-on-close.
 //
@@ -1031,27 +1119,120 @@ static void WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stre
 //
 //==========================================================================
 
-static HANDLE MakeTar (bool &gzip)
+static HANDLE MakeZip ()
 {
-	DWORD len;
-	unsigned char gzipheader[10];
-	tar::record record;
-	Bytef outbuf[sizeof(record)];
+	zip::CentralDirectoryEntry central = { ZIP_CENTRALFILE, { 20, 0 }, { 20, 0 }, };
+	zip::EndOfCentralDirectory dirend = { ZIP_ENDOFDIR, };
+	short dosdate, dostime;
 	time_t now;
-	int i, j, sum;
+	struct tm *nowtm;
+	int i, numfiles;
 	HANDLE file;
-	DWORD filesize, k;
-	DWORD totalsize;
-	z_stream stream;
-	int err;
-	DWORD crc;
+	DWORD len, dirsize;
 
 	if (NumFiles == 0)
 	{
 		return INVALID_HANDLE_VALUE;
 	}
 
+	// Open the zip file.
+	file = CreateTempFile ();
+	if (file == INVALID_HANDLE_VALUE)
+	{
+		return file;
+	}
+
 	time (&now);
+	nowtm = localtime (&now);
+
+	if (nowtm == NULL || nowtm->tm_year < 80)
+	{
+		dosdate = dostime = 0;
+	}
+	else
+	{
+		dosdate = (nowtm->tm_year - 80) * 512 + (nowtm->tm_mon + 1) * 32 + nowtm->tm_mday;
+		dostime = nowtm->tm_hour * 2048 + nowtm->tm_min * 32 + nowtm->tm_sec / 2;
+		dosdate = LittleShort(dosdate);
+		dostime = LittleShort(dostime);
+	}
+
+	// Write out the zip archive, one file at a time
+	for (i = 0; i < NumFiles; ++i)
+	{
+		AddZipFile (file, &TarFiles[i], dosdate, dostime);
+	}
+
+	// Write the central directory
+	central.ModTime = dostime;
+	central.ModDate = dosdate;
+	central.InternalAttributes = LittleShort(1);
+
+	dirend.DirectoryOffset = LittleLong(SetFilePointer (file, 0, NULL, FILE_CURRENT));
+
+	for (i = 0, numfiles = 0, dirsize = 0; i < NumFiles; ++i)
+	{
+		// Skip empty files
+		if (TarFiles[i].UncompressedSize == 0)
+		{
+			continue;
+		}
+		numfiles++;
+		if (TarFiles[i].Deflated)
+		{
+			central.Flags = LittleShort(2);
+			central.Method = LittleShort(8);
+		}
+		else
+		{
+			central.Flags = 0;
+			central.Method = 0;
+		}
+		central.CRC32 = LittleLong(TarFiles[i].CRC32);
+		central.CompressedSize = LittleLong(TarFiles[i].CompressedSize);
+		central.UncompressedSize = LittleLong(TarFiles[i].UncompressedSize);
+		central.NameLength = LittleShort((WORD)strlen(TarFiles[i].Filename));
+		central.LocalHeaderOffset = LittleLong(TarFiles[i].ZipOffset);
+		WriteFile (file, &central, sizeof(central), &len, NULL);
+		WriteFile (file, TarFiles[i].Filename, (DWORD)strlen(TarFiles[i].Filename), &len, NULL);
+		dirsize += sizeof(central) + len;
+	}
+
+	// Write the directory terminator
+	dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort(numfiles);
+	dirend.DirectorySize = LittleLong(dirsize);
+	WriteFile (file, &dirend, sizeof(dirend), &len, NULL);
+
+	return file;
+}
+
+//==========================================================================
+//
+// AddZipFile
+//
+// Adds a file to the opened zip.
+//
+//==========================================================================
+
+static void AddZipFile (HANDLE ziphandle, TarFile *whichfile, short dosdate, short dostime)
+{
+	zip::LocalFileHeader local = { ZIP_LOCALFILE, };
+	Bytef outbuf[1024], inbuf[1024];
+	z_stream stream;
+	DWORD wrote, len, k;
+	int err;
+	bool gzip;
+
+	whichfile->UncompressedSize = GetFileSize (whichfile->File, NULL);
+	whichfile->CompressedSize = 0;
+	whichfile->ZipOffset = 0;
+	whichfile->Deflated = false;
+
+	// Skip empty files.
+	if (whichfile->UncompressedSize == 0)
+	{
+		return;
+	}
 
 	stream.next_in = Z_NULL;
 	stream.avail_in = 0;
@@ -1061,89 +1242,42 @@ static HANDLE MakeTar (bool &gzip)
 		8, Z_DEFAULT_STRATEGY);
 	gzip = err == Z_OK;
 
-	// Open the tar file.
-	file = CreateTempFile ();
-	if (file == INVALID_HANDLE_VALUE)
+	if (gzip)
 	{
-		if (gzip)
-		{
-			deflateEnd (&stream);
-		}
-		return file;
-	}
-
-	if (gzip = (err == Z_OK))
-	{
-		// Write GZIP header
-		memcpy (gzipheader,   "\x1F\x8B\x08\x00    \x02\x0B", 10);
-		memcpy (gzipheader+4, &now, 4);
-		WriteFile (file, gzipheader, 10, &len, NULL);
-		crc = crc32 (0, NULL, 0);
+		local.Method = LittleShort(8);
+		whichfile->Deflated = true;
 		stream.next_out = outbuf;
 		stream.avail_out = sizeof(outbuf);
 	}
 
-	// Write out the tar archive, one file at a time
-	for (i = 0, totalsize = 0; i < NumFiles; ++i)
+	// Write out the header and filename.
+	local.VersionToExtract[0] = 20;
+	local.Flags = gzip ? LittleShort(2) : 0;
+	local.ModTime = dostime;
+	local.ModDate = dosdate;
+	local.UncompressedSize = LittleLong(whichfile->UncompressedSize);
+	local.NameLength = LittleShort((WORD)strlen(whichfile->Filename));
+	
+	whichfile->ZipOffset = SetFilePointer (ziphandle, 0, NULL, FILE_CURRENT);
+	WriteFile (ziphandle, &local, sizeof(local), &wrote, NULL);
+	WriteFile (ziphandle, whichfile->Filename, (DWORD)strlen(whichfile->Filename), &wrote, NULL);
+
+	// Write the file itself and calculate its CRC.
+	SetFilePointer (whichfile->File, 0, NULL, FILE_BEGIN);
+	for (k = 0; k < whichfile->UncompressedSize; )
 	{
-		// Fill in header information
-		filesize = GetFileSize (TarFiles[i].File, NULL);
-
-		// Skip empty files
-		if (filesize == 0)
+		len = whichfile->UncompressedSize - k;
+		if (len > 1024)
 		{
-			continue;
-		}
-
-		memset (&record, 0, sizeof(record));
-		strcpy (record.header.name,  TarFiles[i].Filename);
-		strcpy (record.header.mode,  "000666 ");
-		strcpy (record.header.uid,   "     0 ");
-		strcpy (record.header.gid,   "     0 ");
-		strcpy (record.header.magic, "ustar  ");
-		strcpy (record.header.uname, "zdoom");
-		strcpy (record.header.gname, "games");
-		sprintf(record.header.size,  "%11lo ", filesize);
-		sprintf(record.header.mtime, "%11lo ", now);
-		record.header.linkflag =     '0';
-
-		// Calculate checksum
-		memcpy (record.header.chksum, "        ", 8);
-		for (j = 0, sum = 0; j < (int)sizeof(record); ++j)
-		{
-			sum += record.charptr[j];
-		}
-		sprintf (record.header.chksum, "%6o", sum);
-
-		// Write out the header and then the file (padded to 512 bytes)
-		WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
-		totalsize += sizeof(record);
-
-		SetFilePointer (TarFiles[i].File, 0, NULL, FILE_BEGIN);
-		for (k = 0; k < filesize; k += 512)
-		{
-			len = filesize - k;
-			if (len > sizeof(record))
-			{
-				len = sizeof(record);
-			}
-			else
-			{
-				memset (&record.charptr[len], 0, sizeof(record)-len);
-			}
-			ReadFile (TarFiles[i].File, &record, len, &len, NULL);
-			WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
-			totalsize += sizeof(record);
+			len = 1024;
 		}
+		k += len;
+		ReadFile (whichfile->File, &inbuf, len, &len, NULL);
+		whichfile->CRC32 = crc32 (whichfile->CRC32, inbuf, len);
+		whichfile->CompressedSize += WriteBlock (ziphandle, inbuf, len, gzip ? &stream : NULL, outbuf);
 	}
 
-	// EOT is two zeroed blocks, according to GNU tar.
-	memset (&record, 0, sizeof(record));
-	WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
-	WriteBlock (file, &record, sizeof(record), gzip ? &stream : NULL, outbuf, &crc);
-	totalsize += 2*sizeof(record);
-
-	// Flush the zlib stream buffer and write the gzip epilogue
+	// Flush the zlib stream buffer.
 	if (gzip)
 	{
 		for (bool done = false;;)
@@ -1151,7 +1285,8 @@ static HANDLE MakeTar (bool &gzip)
 			len = sizeof(outbuf) - stream.avail_out;
 			if (len != 0)
 			{
-				WriteFile (file, outbuf, len, &len, NULL);
+				whichfile->CompressedSize += len;
+				WriteFile (ziphandle, outbuf, len, &wrote, NULL);
 				stream.next_out = outbuf;
 				stream.avail_out = sizeof(outbuf);
 			}
@@ -1167,14 +1302,17 @@ static HANDLE MakeTar (bool &gzip)
 			}
 		}
 		deflateEnd (&stream);
-		memcpy (gzipheader,   &crc, 4);
-		memcpy (gzipheader+4, &totalsize, 4);
-		WriteFile (file, gzipheader, 8, &len, NULL);
 	}
-	return file;
-}
 
-static WNDPROC StdStaticProc;
+	// Fill in fields we didn't know when we wrote the local header.
+	SetFilePointer (ziphandle, whichfile->ZipOffset + 14, NULL, FILE_BEGIN);
+	k = LittleLong(whichfile->CRC32);
+	WriteFile (ziphandle, &k, 4, &wrote, NULL);
+	k = LittleLong(whichfile->CompressedSize);
+	WriteFile (ziphandle, &k, 4, &wrote, NULL);
+
+	SetFilePointer (ziphandle, 0, NULL, FILE_END);
+}
 
 //==========================================================================
 //
@@ -2301,7 +2439,6 @@ struct UploadParmStruct
 	HWND hDlg;
 	HANDLE hThread;
 	HANDLE hFile;
-	bool gzipped;
 	const char *UserSummary;
 };
 
@@ -2394,10 +2531,6 @@ static DWORD WINAPI UploadProc (LPVOID lpParam)
 						sizeof(MultipartBinaryHeader)-1 +
 						sizeof(MultipartHeaderGZip)-1 + fileLen +
 						sizeof(MultipartFooter)-1;
-		if (!parm->gzipped)
-		{
-			contentLength -= sizeof(MultipartHeaderGZip) - sizeof(MultipartHeaderNoGZip);
-		}
 		headerLen = sprintf (xferbuf, PostHeader, contentLength);
 		bytesSent = send (sock, xferbuf, headerLen, 0);
 		if (bytesSent != headerLen)
@@ -2463,8 +2596,7 @@ static DWORD WINAPI UploadProc (LPVOID lpParam)
 		}
 
 		// Send the report file.
-		headerLen = sprintf (xferbuf, "%s%s", MultipartBinaryHeader,
-			parm->gzipped ? MultipartHeaderGZip : MultipartHeaderNoGZip);
+		headerLen = sprintf (xferbuf, "%s%s", MultipartBinaryHeader, MultipartHeaderZip);
 
 		bytesSent = send (sock, xferbuf, headerLen, 0);
 		if (bytesSent == SOCKET_ERROR)
@@ -2684,9 +2816,9 @@ static BOOL CALLBACK BoingDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARA
 //
 //==========================================================================
 
-static BOOL UploadReport (HANDLE file, bool gzipped)
+static BOOL UploadReport (HANDLE file)
 {
-	UploadParmStruct uploadParm = { 0, 0, file, gzipped, UserSummary };
+	UploadParmStruct uploadParm = { 0, 0, file, UserSummary };
 	BOOL res = (BOOL)DialogBoxParam (g_hInst, MAKEINTRESOURCE(IDD_BOING), NULL, (DLGPROC)BoingDlgProc, (LPARAM)&uploadParm);
 	if (UserSummary != NULL)
 	{
@@ -2706,7 +2838,7 @@ static BOOL UploadReport (HANDLE file, bool gzipped)
 //
 //==========================================================================
 
-static void SaveReport (HANDLE file, bool gzipped)
+static void SaveReport (HANDLE file)
 {
 	OPENFILENAME ofn = {
 #ifdef OPENFILENAME_SIZE_VERSION_400
@@ -2717,16 +2849,8 @@ static void SaveReport (HANDLE file, bool gzipped)
 		, };
 	char filename[256];
 
-	if (gzipped)
-	{
-		ofn.lpstrFilter = "GZipped Tarball (*.tar.gz)\0*.tar.gz\0";
-		strcpy (filename, "CrashReport.tar.gz");
-	}
-	else
-	{
-		ofn.lpstrFilter = "Tarball (*.tar)\0*.tar\0";
-		strcpy (filename, "CrashReport.tar");
-	}
+	ofn.lpstrFilter = "Zip file (*.pk3)\0*.pk3\0";
+	strcpy (filename, "CrashReport.pk3");
 	ofn.lpstrFile = filename;
 	ofn.nMaxFile = sizeof(filename);
 
@@ -2780,7 +2904,6 @@ void DisplayCrashLog ()
 {
 	HINSTANCE riched;
 	HANDLE file;
-	bool gzipped = false;
 
 	if (NumFiles == 0 || (riched = LoadLibrary ("riched20.dll")) == NULL)
 	{
@@ -2805,16 +2928,16 @@ void DisplayCrashLog ()
 		INT_PTR result = DialogBox (g_hInst, MAKEINTRESOURCE(IDD_CRASHDIALOG), NULL, (DLGPROC)CrashDlgProc);
 		if (result == IDYES)
 		{
-#if 0	// Server-side support is not done yet
-			file = MakeTar (gzipped);
-			UploadReport (file, gzipped);
+#if 0	// Server-side support is not done yet because I am too lazy.
+			file = MakeZip ();
+			UploadReport (file);
 			CloseHandle (file);
 #endif
 		}
 		else if (result == IDC_SAVEREPORT)
 		{
-			file = MakeTar (gzipped);
-			SaveReport (file, gzipped);
+			file = MakeZip ();
+			SaveReport (file);
 			CloseHandle (file);
 		}
 		FreeLibrary (riched);
diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp
index 410d2d857..74444512d 100644
--- a/src/win32/i_main.cpp
+++ b/src/win32/i_main.cpp
@@ -67,11 +67,9 @@
 
 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 
-void CreateCrashLog (HANDLE process, DWORD processID, DWORD threadID, LPEXCEPTION_POINTERS exceptionRecord, char *custominfo, DWORD customsize);
+void CreateCrashLog (char *custominfo, DWORD customsize);
 extern void DisplayCrashLog ();
 extern EXCEPTION_POINTERS CrashPointers;
-extern EXCEPTION_RECORD MyExceptionRecord;
-extern CONTEXT MyContextRecord;
 
 // Will this work with something besides VC++?
 // Answer: yes it will.
@@ -479,15 +477,7 @@ LONG WINAPI ExitMessedUp (LPEXCEPTION_POINTERS foo)
 	ExitProcess (1000);
 }
 
-void CALLBACK TimeToDie (ULONG_PTR dummy)
-{
-	SetUnhandledExceptionFilter (ExitMessedUp);
-	I_ShutdownHardware ();
-	SetWindowPos (Window, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
-	exit (-1);
-}
-
-void CALLBACK SpawnFailed (ULONG_PTR dummy)
+void CALLBACK ExitFatally (ULONG_PTR dummy)
 {
 	SetUnhandledExceptionFilter (ExitMessedUp);
 	I_ShutdownHardware ();
@@ -496,30 +486,8 @@ void CALLBACK SpawnFailed (ULONG_PTR dummy)
 	exit (-1);
 }
 
-void GetInfo (PEXCEPTION_POINTERS dst, PEXCEPTION_POINTERS src)
-{
-	dst->ExceptionRecord = &MyExceptionRecord;
-	dst->ContextRecord = &MyContextRecord;
-	MyExceptionRecord = *src->ExceptionRecord;
-	MyContextRecord = *src->ContextRecord;
-}
-
 LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info)
 {
-	static bool caughtsomething = false;
-
-	if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER;
-	caughtsomething = true;
-
-	char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384);
-	PAPCFUNC apcfunc;
-	char cmdline[128];
-	char modname[_MAX_PATH];
-	STARTUPINFO startup = { sizeof(startup) };
-	PROCESS_INFORMATION newproc;
-
-	GetInfo (&CrashPointers, info);
-
 #ifdef _DEBUG
 	if (info->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
 	{
@@ -527,41 +495,27 @@ LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info)
 	}
 #endif
 
+	static bool caughtsomething = false;
+
+	if (caughtsomething) return EXCEPTION_EXECUTE_HANDLER;
+	caughtsomething = true;
+
+	char *custominfo = (char *)HeapAlloc (GetProcessHeap(), 0, 16384);
+
 	CrashPointers = *info;
 	DoomSpecificInfo (custominfo);
-
-	// Spawn off a new copy of ourself to handle the information gathering and reporting.
-	wsprintf (cmdline, "IDidCrash:OuchieBooboo %x %x %p %p %lx", GetCurrentProcessId(),
-		GetCurrentThreadId(), &CrashPointers, custominfo, strlen(custominfo));
-	GetModuleFileName (NULL, modname, _MAX_PATH);
-	modname[_MAX_PATH-1] = 0;
-	if (!CreateProcess (modname, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &newproc))
-	{
-		// CreateProcess failed. We'll have to do everything ourself!
-		CreateCrashLog (GetCurrentProcess(), GetCurrentProcessId(), GetCurrentThreadId(), &CrashPointers, custominfo, (DWORD)strlen(custominfo));
-		apcfunc = SpawnFailed;
-		QueueUserAPC (SpawnFailed, MainThread, 0);
-	}
-	else
-	{
-		// Give our new debugger process a chance to get up and running and attach
-		// itself to us. Calling SuspendThread (so that we wait only as long as actually
-		// needed) does not work, because it interferes with the receipt of the
-		// exception information. I'm not sure why.
-		Sleep (1000);
-		apcfunc = TimeToDie;
-	}
+	CreateCrashLog (custominfo, (DWORD)strlen(custominfo));
 
 	// If the main thread crashed, then make it clean up after itself.
 	// Otherwise, put the crashing thread to sleep and signal the main thread to clean up.
 	if (GetCurrentThreadId() == MainThreadID)
 	{
-		info->ContextRecord->Eip = (DWORD_PTR)apcfunc;
+		info->ContextRecord->Eip = (DWORD_PTR)ExitFatally;
 	}
 	else
 	{
 		info->ContextRecord->Eip = (DWORD_PTR)SleepForever;
-		QueueUserAPC (apcfunc, MainThread, 0);
+		QueueUserAPC (ExitFatally, MainThread, 0);
 	}
 	return EXCEPTION_CONTINUE_EXECUTION;
 }
@@ -572,63 +526,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n
 
 	InitCommonControls ();	// Be pretty under XP
 
-	if (strncmp (GetCommandLine(), "IDidCrash:OuchieBooboo ", 23) == 0 && __argc == 6)
-	{ // We are being run to handle a crash in another instance of ourself.
-	  // argv[1] is the process ID of the instance that crashed.
-	  // argv[2] is the thread ID of the crasher.
-	  // argv[3] is a pointer to the exception information in that process's address space.
-	  // argv[4] is a pointer to a text buffer for ZDoom-specific info.
-	  // argv[5] is the length of argv[4]'s buffer
-		DWORD pid, tid;
-		LPEXCEPTION_POINTERS info;
-		char *info2;
-		DWORD info2len;
-		BOOL debugging;
-		HANDLE debuggee;
-		DEBUG_EVENT debugev;
-
-		pid = strtoul (__argv[1], NULL, 16);
-		tid = strtoul (__argv[2], NULL, 16);
-		sscanf (__argv[3], "%p", &info);
-		sscanf (__argv[4], "%p", &info2);
-		info2len = strtoul (__argv[5], NULL, 16);
-
-		// DebugActiveProcess will suspend all threads in the other process,
-		// so that's why we call it. When it resumes, it will shut down
-		// as cleanly as it can.
-		debugging = DebugActiveProcess (pid);
-//		if (MessageBox (NULL, GetCommandLine(), "foo", MB_OKCANCEL) == IDCANCEL) exit (0);
-		debuggee = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
-		CreateCrashLog (debuggee, pid, tid, info, info2, info2len);
-		if (debugging)
-		{ // Now let the crashing process resume. Process debug events until the process
-		  // has exited. We don't care about the events, we just wanted the debugger status
-		  // so that the process would be suspended while we gathered info on it.
-			while (WaitForDebugEvent (&debugev, INFINITE))
-			{
-				ContinueDebugEvent(debugev.dwProcessId, debugev.dwThreadId, DBG_CONTINUE);
-				if (debugev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
-				{
-					// In this case, ContinueDebugEvent closes the process handle for us,
-					// so we don't need to (and we must be sure not to reference it again).
-					break;
-				}
-			}
-		}
-		DisplayCrashLog ();
-		exit (0);
-	}
 #if !defined(__GNUC__) && defined(_DEBUG)
 	if (__argc == 2 && strcmp (__argv[1], "TestCrash") == 0)
 	{
-		EXCEPTION_POINTERS info;
 		__try
 		{
 			*(int *)0 = 0;
 		}
-		__except(GetInfo (&info, GetExceptionInformation()),
-			CreateCrashLog (GetCurrentProcess(), GetCurrentProcessId(), GetCurrentThreadId(), &info, __argv[1], 9),
-			EXCEPTION_EXECUTE_HANDLER)
+		__except(CrashPointers = *GetExceptionInformation(),
+			CreateCrashLog (__argv[1], 9), EXCEPTION_EXECUTE_HANDLER)
 		{
 		}
 		DisplayCrashLog ();