2006-02-24 04:48:15 +00:00
|
|
|
/*
|
|
|
|
** i_crash.cpp
|
|
|
|
** Gathers exception information when the program crashes.
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
2006-06-11 01:37:00 +00:00
|
|
|
** Copyright 2002-2006 Randy Heit
|
2006-02-24 04:48:15 +00:00
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.s
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
2006-05-22 01:34:07 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// HEADER FILES ------------------------------------------------------------
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#define _WIN32_WINNT 0x0501
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winnt.h>
|
|
|
|
#include <richedit.h>
|
|
|
|
#include <winuser.h>
|
|
|
|
#include <tlhelp32.h>
|
2008-08-24 04:51:15 +00:00
|
|
|
#ifndef _M_IX86
|
|
|
|
#include <winternl.h>
|
|
|
|
#endif
|
2006-07-21 22:28:54 +00:00
|
|
|
#ifndef __GNUC__
|
2006-02-24 04:48:15 +00:00
|
|
|
#include <dbghelp.h>
|
2006-07-21 22:28:54 +00:00
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
#include <commctrl.h>
|
|
|
|
#include <commdlg.h>
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <ws2tcpip.h>
|
|
|
|
#include <setupapi.h>
|
|
|
|
#include <uxtheme.h>
|
|
|
|
#include <shellapi.h>
|
|
|
|
#include <uxtheme.h>
|
|
|
|
#include <stddef.h>
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
|
|
|
|
#define USE_WINDOWS_DWORD
|
|
|
|
#include "doomtype.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "resource.h"
|
|
|
|
#include "version.h"
|
2006-06-24 03:47:17 +00:00
|
|
|
#include "m_swap.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <zlib.h>
|
|
|
|
|
2010-09-01 03:30:18 +00:00
|
|
|
#if defined(_WIN64) && defined(__GNUC__)
|
|
|
|
struct KNONVOLATILE_CONTEXT_POINTERS {
|
|
|
|
union {
|
|
|
|
PDWORD64 IntegerContext[16];
|
|
|
|
struct {
|
|
|
|
PDWORD64 Rax;
|
|
|
|
PDWORD64 Rcx;
|
|
|
|
PDWORD64 Rdx;
|
|
|
|
PDWORD64 Rbx;
|
|
|
|
PDWORD64 Rsp;
|
|
|
|
PDWORD64 Rbp;
|
|
|
|
PDWORD64 Rsi;
|
|
|
|
PDWORD64 Rdi;
|
|
|
|
PDWORD64 R8;
|
|
|
|
PDWORD64 R9;
|
|
|
|
PDWORD64 R10;
|
|
|
|
PDWORD64 R11;
|
|
|
|
PDWORD64 R12;
|
|
|
|
PDWORD64 R13;
|
|
|
|
PDWORD64 R14;
|
|
|
|
PDWORD64 R15;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
typedef
|
|
|
|
EXCEPTION_DISPOSITION
|
|
|
|
NTAPI
|
|
|
|
EXCEPTION_ROUTINE (
|
|
|
|
struct _EXCEPTION_RECORD *ExceptionRecord,
|
|
|
|
PVOID EstablisherFrame,
|
|
|
|
struct _CONTEXT *ContextRecord,
|
|
|
|
PVOID DispatcherContext
|
|
|
|
);
|
|
|
|
NTSYSAPI
|
|
|
|
EXCEPTION_ROUTINE *
|
|
|
|
NTAPI
|
|
|
|
RtlVirtualUnwind (
|
|
|
|
DWORD HandlerType,
|
|
|
|
DWORD64 ImageBase,
|
|
|
|
DWORD64 ControlPc,
|
|
|
|
PRUNTIME_FUNCTION FunctionEntry,
|
|
|
|
PCONTEXT ContextRecord,
|
|
|
|
PVOID *HandlerData,
|
|
|
|
PDWORD64 EstablisherFrame,
|
|
|
|
KNONVOLATILE_CONTEXT_POINTERS *ContextPointers
|
|
|
|
);
|
|
|
|
#endif
|
|
|
|
|
2006-07-21 22:36:39 +00:00
|
|
|
// MACROS ------------------------------------------------------------------
|
|
|
|
|
|
|
|
#define REMOTE_HOST "localhost"
|
|
|
|
#define REMOTE_PORT "80"
|
|
|
|
#define UPLOAD_URI "/test.php"
|
|
|
|
#define UPLOAD_BOUNDARY "Von-DnrNbJl0 P9d_BD;cEEsQVWpYMq0pbZ6NUmYHus;yIbFbkgB?.N=YC5O=BGZm+Rab5"
|
|
|
|
#define DBGHELP_URI "/msredist/dbghelp.dl_"
|
|
|
|
|
|
|
|
// 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)
|
2013-06-23 02:49:51 +00:00
|
|
|
#define UPLOAD_AGENT "ZDoom/" VERSIONSTR " (" GAMESIG ")"
|
2006-07-21 22:36:39 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2009-08-31 21:47:29 +00:00
|
|
|
#ifndef __BIG_ENDIAN__
|
2006-07-21 22:36:39 +00:00
|
|
|
#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)
|
|
|
|
|
2006-07-21 22:28:54 +00:00
|
|
|
// DBGHELP.H ---------------------------------------------------------------
|
|
|
|
|
|
|
|
// w32api does not include dbghelp.h, so if I don't include these here,
|
|
|
|
// a person using GCC will need to download the Platform SDK, grab dbghelp.h
|
|
|
|
// from it, and edit it so it works with GCC.
|
|
|
|
#ifdef __GNUC__
|
|
|
|
typedef enum _MINIDUMP_TYPE
|
|
|
|
{
|
|
|
|
MiniDumpNormal
|
|
|
|
// Other types omitted.
|
|
|
|
} MINIDUMP_TYPE;
|
|
|
|
|
|
|
|
typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
|
|
|
|
DWORD ThreadId;
|
|
|
|
PEXCEPTION_POINTERS ExceptionPointers;
|
|
|
|
BOOL ClientPointers;
|
|
|
|
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
|
|
|
|
|
|
|
|
typedef struct _MINIDUMP_USER_STREAM_INFORMATION {
|
|
|
|
ULONG UserStreamCount;
|
|
|
|
void *UserStreamArray; // Not really void *
|
|
|
|
} MINIDUMP_USER_STREAM_INFORMATION, *PMINIDUMP_USER_STREAM_INFORMATION;
|
|
|
|
|
|
|
|
typedef BOOL (WINAPI * MINIDUMP_CALLBACK_ROUTINE) (
|
|
|
|
IN PVOID CallbackParam,
|
|
|
|
IN CONST void *CallbackInput, // Not really void *
|
|
|
|
IN OUT void *CallbackOutput // Not really void *
|
|
|
|
);
|
|
|
|
|
|
|
|
typedef struct _MINIDUMP_CALLBACK_INFORMATION {
|
|
|
|
MINIDUMP_CALLBACK_ROUTINE CallbackRoutine;
|
|
|
|
PVOID CallbackParam;
|
|
|
|
} MINIDUMP_CALLBACK_INFORMATION, *PMINIDUMP_CALLBACK_INFORMATION;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Dbghelp.dll is loaded at runtime so we don't create any needless
|
|
|
|
// dependencies on it.
|
|
|
|
typedef BOOL (WINAPI *THREADWALK) (HANDLE, LPTHREADENTRY32);
|
|
|
|
typedef BOOL (WINAPI *MODULEWALK) (HANDLE, LPMODULEENTRY32);
|
|
|
|
typedef HANDLE (WINAPI *CREATESNAPSHOT) (DWORD, DWORD);
|
2008-03-18 03:01:21 +00:00
|
|
|
typedef BOOL (WINAPI *WRITEDUMP) (HANDLE, DWORD, HANDLE, int,
|
2006-07-21 22:28:54 +00:00
|
|
|
PMINIDUMP_EXCEPTION_INFORMATION,
|
|
|
|
PMINIDUMP_USER_STREAM_INFORMATION,
|
|
|
|
PMINIDUMP_CALLBACK_INFORMATION);
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// TYPES -------------------------------------------------------------------
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
#ifdef _M_X64
|
|
|
|
typedef PRUNTIME_FUNCTION (WINAPI *RTLLOOKUPFUNCTIONENTRY)
|
|
|
|
(ULONG64 ControlPc, PULONG64 ImageBase, void *HistoryTable);
|
|
|
|
#endif
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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;
|
|
|
|
};
|
|
|
|
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
struct MiniDumpThreadData
|
|
|
|
{
|
|
|
|
HANDLE File;
|
|
|
|
WRITEDUMP pMiniDumpWriteDump;
|
|
|
|
MINIDUMP_EXCEPTION_INFORMATION *Exceptor;
|
|
|
|
};
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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);
|
2008-08-24 04:51:15 +00:00
|
|
|
static void AddStackInfo (HANDLE file, void *dumpaddress, DWORD code, CONTEXT *ctxt);
|
|
|
|
static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD *jump, CONTEXT *ctxt);
|
2006-06-24 03:47:17 +00:00
|
|
|
static void AddToolHelp (HANDLE file);
|
|
|
|
|
|
|
|
static HANDLE WriteTextReport ();
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
static DWORD WINAPI WriteMiniDumpInAnotherThread (LPVOID lpParam);
|
2006-06-24 03:47:17 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
static const char PostHeader[] =
|
|
|
|
"POST " UPLOAD_URI " HTTP/1.1\r\n"
|
|
|
|
"Host: " REMOTE_HOST "\r\n"
|
|
|
|
"Connection: Close\r\n"
|
|
|
|
"User-Agent: " UPLOAD_AGENT "\r\n"
|
|
|
|
"Expect: 100-continue\r\n"
|
|
|
|
"Content-Type: multipart/form-data; boundary=\"" UPLOAD_BOUNDARY "\"\r\n"
|
|
|
|
"Content-Length: %lu\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static const char MultipartInfoHeader[] =
|
|
|
|
"\r\n--" UPLOAD_BOUNDARY "\r\n"
|
|
|
|
"Content-Transfer-Encoding: 7bit\r\n"
|
|
|
|
"Content-Disposition: form-data; name=\"Info\"\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static const char MultipartUserSummaryHeader[] =
|
|
|
|
"\r\n--" UPLOAD_BOUNDARY "\r\n"
|
|
|
|
"Content-Transfer-Encoding: 8bit\r\n"
|
|
|
|
"Content-Disposition: form-data; name=\"UserSummary\"\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static const char MultipartBinaryHeader[] =
|
|
|
|
"\r\n--" UPLOAD_BOUNDARY "\r\n"
|
|
|
|
"Content-Transfer-Encoding: binary\r\n"
|
|
|
|
"Content-Disposition: form-data; name=\"reportfile\"; filename=\"itdidcrash.tar";
|
|
|
|
|
|
|
|
static const char MultipartHeaderGZip[] =
|
|
|
|
".gz\"\r\n"
|
|
|
|
"Content-Type: application/x-tar-gz\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static const char MultipartHeaderNoGZip[] =
|
|
|
|
"\"\r\n"
|
|
|
|
"Content-Type: application/x-tar\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static const char MultipartFooter[] =
|
|
|
|
"\r\n--" UPLOAD_BOUNDARY "--\r\n\r\n";
|
|
|
|
|
|
|
|
static const char DbgHelpRequest[] =
|
|
|
|
"GET " DBGHELP_URI " HTTP/1.1\r\n"
|
|
|
|
"Host: " REMOTE_HOST "\r\n"
|
|
|
|
"Connection: Close\r\n"
|
|
|
|
"User-Agent: " UPLOAD_AGENT "\r\n"
|
|
|
|
"\r\n";
|
|
|
|
|
|
|
|
static TarFile TarFiles[MAX_FILES];
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static int NumFiles;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
static HANDLE DbgProcess;
|
|
|
|
static DWORD DbgProcessID;
|
|
|
|
static DWORD DbgThreadID;
|
|
|
|
static DWORD CrashCode;
|
|
|
|
static PVOID CrashAddress;
|
|
|
|
static bool NeedDbgHelp;
|
|
|
|
static char CrashSummary[256];
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static WNDPROC StdStaticProc;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// CODE --------------------------------------------------------------------
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// SafeReadMemory
|
|
|
|
//
|
|
|
|
// Returns true if the memory was succussfully read and false if not.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static bool SafeReadMemory (const void *base, void *buffer, size_t len)
|
|
|
|
{
|
2006-07-21 22:36:39 +00:00
|
|
|
#ifdef __GNUC__
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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.
|
2006-07-21 22:36:39 +00:00
|
|
|
|
|
|
|
if (IsBadReadPtr (base, len))
|
2006-06-24 03:47:17 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2006-07-21 22:36:39 +00:00
|
|
|
memcpy (buffer, base, len);
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
// Non-GCC version: Use SEH to catch any bad reads immediately when
|
|
|
|
// they happen instead of trying to catch them beforehand.
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
__try
|
|
|
|
{
|
|
|
|
memcpy (buffer, base, len);
|
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
return success;
|
2006-07-21 22:36:39 +00:00
|
|
|
#endif
|
2006-06-24 03:47:17 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// GetTopOfStack
|
|
|
|
//
|
|
|
|
// Given a pointer to some address on the stack, returns a pointer to
|
|
|
|
// the top of the stack.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
DWORD *GetTopOfStack (void *top)
|
|
|
|
{
|
|
|
|
MEMORY_BASIC_INFORMATION memInfo;
|
|
|
|
|
|
|
|
if (VirtualQuery (top, &memInfo, sizeof(memInfo)))
|
|
|
|
{
|
|
|
|
return (DWORD *)((BYTE *)memInfo.BaseAddress + memInfo.RegionSize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteMyMiniDump
|
|
|
|
//
|
|
|
|
// Writes a minidump if dbghelp.dll is present and adds it to the tarball.
|
|
|
|
// Otherwise, it just returns INVALID_HANDLE_VALUE.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static HANDLE WriteMyMiniDump (void)
|
|
|
|
{
|
|
|
|
MINIDUMP_EXCEPTION_INFORMATION exceptor = { DbgThreadID, &CrashPointers, FALSE };
|
|
|
|
char dbghelpPath[MAX_PATH+12], *bs;
|
|
|
|
WRITEDUMP pMiniDumpWriteDump;
|
|
|
|
HANDLE file;
|
|
|
|
BOOL good = FALSE;
|
|
|
|
HMODULE dbghelp = NULL;
|
|
|
|
|
|
|
|
// Make sure dbghelp.dll and MiniDumpWriteDump are available
|
|
|
|
// Try loading from the application directory first, then from the search path.
|
|
|
|
GetModuleFileName (NULL, dbghelpPath, MAX_PATH);
|
|
|
|
dbghelpPath[MAX_PATH] = 0;
|
|
|
|
bs = strrchr (dbghelpPath, '\\');
|
|
|
|
if (bs != NULL)
|
|
|
|
{
|
|
|
|
strcpy (bs + 1, "dbghelp.dll");
|
|
|
|
dbghelp = LoadLibrary (dbghelpPath);
|
|
|
|
}
|
|
|
|
if (dbghelp == NULL)
|
|
|
|
{
|
|
|
|
dbghelp = LoadLibrary ("dbghelp.dll");
|
|
|
|
if (dbghelp == NULL)
|
|
|
|
{
|
|
|
|
NeedDbgHelp = true;
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pMiniDumpWriteDump = (WRITEDUMP)GetProcAddress (dbghelp, "MiniDumpWriteDump");
|
|
|
|
if (pMiniDumpWriteDump != NULL)
|
|
|
|
{
|
|
|
|
file = CreateTempFile ();
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
if (CrashPointers.ExceptionRecord->ExceptionCode != EXCEPTION_STACK_OVERFLOW)
|
|
|
|
{
|
|
|
|
good = pMiniDumpWriteDump (DbgProcess, DbgProcessID, file,
|
2008-03-18 03:01:21 +00:00
|
|
|
#if 1
|
|
|
|
MiniDumpNormal
|
|
|
|
#else
|
|
|
|
MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithPrivateReadWriteMemory
|
|
|
|
#endif
|
|
|
|
, &exceptor, NULL, NULL);
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MiniDumpThreadData dumpdata = { file, pMiniDumpWriteDump, &exceptor };
|
|
|
|
DWORD id;
|
|
|
|
HANDLE thread = CreateThread (NULL, 0, WriteMiniDumpInAnotherThread,
|
|
|
|
&dumpdata, 0, &id);
|
|
|
|
WaitForSingleObject (thread, INFINITE);
|
|
|
|
if (GetExitCodeThread (thread, &id))
|
|
|
|
{
|
|
|
|
good = id;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NeedDbgHelp = true;
|
|
|
|
}
|
|
|
|
return good ? file : INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteMiniDumpInAnotherThread
|
|
|
|
//
|
|
|
|
// When a stack overflow occurs, there isn't enough room left on the stack
|
|
|
|
// for MiniDumpWriteDump to do its thing, so we create a new thread with
|
|
|
|
// a new stack to do the work.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static DWORD WINAPI WriteMiniDumpInAnotherThread (LPVOID lpParam)
|
|
|
|
{
|
|
|
|
MiniDumpThreadData *dumpdata = (MiniDumpThreadData *)lpParam;
|
|
|
|
return dumpdata->pMiniDumpWriteDump (DbgProcess, DbgProcessID,
|
|
|
|
dumpdata->File, MiniDumpNormal, dumpdata->Exceptor, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Writef
|
|
|
|
//
|
|
|
|
// Like printf, but for Win32 file HANDLEs.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void __cdecl Writef (HANDLE file, const char *format, ...)
|
|
|
|
{
|
|
|
|
char buffer[1024];
|
|
|
|
va_list args;
|
|
|
|
DWORD len;
|
|
|
|
|
|
|
|
va_start (args, format);
|
|
|
|
len = vsprintf (buffer, format, args);
|
|
|
|
va_end (args);
|
|
|
|
WriteFile (file, buffer, len, &len, NULL);
|
|
|
|
}
|
|
|
|
|
2010-03-04 02:17:34 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteLogFileStreamer
|
|
|
|
//
|
|
|
|
// The callback function to stream a Rich Edit's contents to a file.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
|
|
|
|
{
|
|
|
|
DWORD didwrite;
|
|
|
|
LONG p, pp;
|
|
|
|
|
|
|
|
// Replace gray foreground color with black.
|
|
|
|
static const char *badfg = "\\red223\\green223\\blue223;";
|
|
|
|
// 4321098 765432109 876543210
|
|
|
|
// 2 1 0
|
|
|
|
for (p = pp = 0; p < cb; ++p)
|
|
|
|
{
|
|
|
|
if (buffer[p] == badfg[pp])
|
|
|
|
{
|
|
|
|
++pp;
|
|
|
|
if (pp == 25)
|
|
|
|
{
|
|
|
|
buffer[p - 1] = buffer[p - 2] = buffer[p - 3] =
|
|
|
|
buffer[p - 9] = buffer[p -10] = buffer[p -11] =
|
|
|
|
buffer[p -18] = buffer[p -19] = buffer[p -20] = '0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pp = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WriteFile((HANDLE)cookie, buffer, cb, &didwrite, NULL))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*pcb = didwrite;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteLogFile
|
|
|
|
//
|
|
|
|
// Writes the contents of a Rich Edit control to a file.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
HANDLE WriteLogFile(HWND edit)
|
|
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
|
|
|
|
file = CreateTempFile();
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
EDITSTREAM streamer = { (DWORD_PTR)file, 0, WriteLogFileStreamer };
|
|
|
|
SendMessage(edit, EM_STREAMOUT, SF_RTF, (LPARAM)&streamer);
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CreateCrashLog
|
|
|
|
//
|
|
|
|
// Creates all the files needed for a crash report.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2010-03-04 02:17:34 +00:00
|
|
|
void CreateCrashLog (char *custominfo, DWORD customsize, HWND richlog)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// Do not collect information more than once.
|
|
|
|
if (NumFiles != 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
DbgThreadID = GetCurrentThreadId();
|
|
|
|
DbgProcessID = GetCurrentProcessId();
|
|
|
|
DbgProcess = GetCurrentProcess();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
CrashCode = CrashPointers.ExceptionRecord->ExceptionCode;
|
|
|
|
CrashAddress = CrashPointers.ExceptionRecord->ExceptionAddress;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
AddFile (WriteTextReport(), "report.txt");
|
|
|
|
AddFile (WriteMyMiniDump(), "minidump.mdmp");
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
BYTE buffer[512];
|
|
|
|
DWORD left;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
for (;; customsize -= left, custominfo += left)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
left = customsize > 512 ? 512 : customsize;
|
|
|
|
if (left == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (SafeReadMemory (custominfo, buffer, left))
|
|
|
|
{
|
|
|
|
WriteFile (file, buffer, left, &wrote, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Writef (file, "Failed reading remaining %lu bytes\r\n", customsize);
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
AddFile (file, "local.txt");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-04 02:17:34 +00:00
|
|
|
if (richlog != NULL)
|
|
|
|
{
|
|
|
|
AddFile (WriteLogFile(richlog), "log.rtf");
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
CloseHandle (DbgProcess);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteTextReport
|
|
|
|
//
|
|
|
|
// This is the classic plain-text report ZDoom has generated since it
|
|
|
|
// added crash gathering abilities in 2002.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
HANDLE WriteTextReport ()
|
|
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
DWORD Code; const char *Text;
|
|
|
|
}
|
|
|
|
exceptions[] =
|
|
|
|
{
|
|
|
|
{ EXCEPTION_ACCESS_VIOLATION, "Access Violation" },
|
|
|
|
{ EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array Bounds Exceeded" },
|
|
|
|
{ EXCEPTION_BREAKPOINT, "Breakpoint" },
|
|
|
|
{ EXCEPTION_DATATYPE_MISALIGNMENT, "Data Type Misalignment" },
|
2012-07-06 02:29:00 +00:00
|
|
|
{ EXCEPTION_FLT_DENORMAL_OPERAND, "Floating Point Denormal Operand." },
|
|
|
|
{ EXCEPTION_FLT_DIVIDE_BY_ZERO, "Floating Point Divide By Zero" },
|
|
|
|
{ EXCEPTION_FLT_INEXACT_RESULT, "Floating Point Inexact Result" },
|
|
|
|
{ EXCEPTION_FLT_INVALID_OPERATION, "Floating Point Invalid Operation" },
|
|
|
|
{ EXCEPTION_FLT_OVERFLOW, "Floating Point Overflow" },
|
|
|
|
{ EXCEPTION_FLT_STACK_CHECK, "Floating Point Stack Check" },
|
|
|
|
{ EXCEPTION_FLT_UNDERFLOW, "Floating Point Underflow" },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal Instruction" },
|
|
|
|
{ EXCEPTION_IN_PAGE_ERROR, "In Page Error" },
|
2012-07-06 02:29:00 +00:00
|
|
|
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer Divide By Zero" },
|
|
|
|
{ EXCEPTION_INT_OVERFLOW, "Integer Overflow" },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ EXCEPTION_INVALID_DISPOSITION, "Invalid Disposition" },
|
|
|
|
{ EXCEPTION_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception" },
|
|
|
|
{ EXCEPTION_PRIV_INSTRUCTION, "Priviledged Instruction" },
|
|
|
|
{ EXCEPTION_SINGLE_STEP, "Single Step" },
|
|
|
|
{ EXCEPTION_STACK_OVERFLOW, "Stack Overflow" }
|
|
|
|
};
|
|
|
|
static const char eflagsBits[][2] =
|
|
|
|
{
|
|
|
|
{ 'C','F' }, // Carry Flag
|
|
|
|
{ 'x','1' }, // Always one
|
|
|
|
{ 'P','F' }, // Parity Flag
|
|
|
|
{ 'x','0' }, // Always zero
|
|
|
|
{ 'A','F' }, // Auxilliary Carry Flag
|
|
|
|
{ 'x','0' }, // Always zero
|
|
|
|
{ 'Z','F' }, // Zero Flag
|
|
|
|
{ 'S','F' }, // Sign Flag
|
|
|
|
{ 'T','F' }, // Trap Flag
|
|
|
|
{ 'I','F' }, // Interrupt Enable Flag
|
|
|
|
{ 'D','F' }, // Direction Flag
|
|
|
|
{ 'O','F' }, // Overflow Flag
|
|
|
|
{ 'x','x' }, // IOPL low bit
|
|
|
|
{ 'x','x' }, // IOPL high bit
|
|
|
|
{ 'N','T' }, // Nested Task
|
|
|
|
{ 'x','0' }, // Always zero
|
|
|
|
{ 'R','F' }, // Resume Flag
|
|
|
|
{ 'V','M' }, // Virtual-8086 Mode
|
|
|
|
{ 'A','C' }, // Alignment Check
|
|
|
|
{ 'V','I' }, // Virtual Interrupt Flag
|
|
|
|
{ 'V','P' } // Virtual Interrupt Pending
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
file = CreateTempFile ();
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSVERSIONINFO verinfo = { sizeof(verinfo) };
|
|
|
|
GetVersionEx (&verinfo);
|
|
|
|
|
|
|
|
for (i = 0; (size_t)i < sizeof(exceptions)/sizeof(exceptions[0]); ++i)
|
|
|
|
{
|
|
|
|
if (exceptions[i].Code == CrashPointers.ExceptionRecord->ExceptionCode)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
j = mysnprintf (CrashSummary, countof(CrashSummary), "Code: %08lX", CrashPointers.ExceptionRecord->ExceptionCode);
|
2006-02-24 04:48:15 +00:00
|
|
|
if ((size_t)i < sizeof(exceptions)/sizeof(exceptions[0]))
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
j += mysnprintf (CrashSummary + j, countof(CrashSummary) - j, " (%s", exceptions[i].Text);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (CrashPointers.ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
|
|
|
{
|
|
|
|
// Pre-NT kernels do not seem to provide this information.
|
|
|
|
if (verinfo.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
j += mysnprintf (CrashSummary + j, countof(CrashSummary) - j,
|
2008-08-24 04:51:15 +00:00
|
|
|
" - tried to %s address %p",
|
2006-02-24 04:48:15 +00:00
|
|
|
CrashPointers.ExceptionRecord->ExceptionInformation[0] ? "write" : "read",
|
2008-08-24 04:51:15 +00:00
|
|
|
(void *)CrashPointers.ExceptionRecord->ExceptionInformation[1]);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CrashSummary[j++] = ')';
|
|
|
|
}
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
j += mysnprintf (CrashSummary + j, countof(CrashSummary) - j, "\r\nAddress: %p", CrashPointers.ExceptionRecord->ExceptionAddress);
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file, "%s\r\nFlags: %08X\r\n\r\n", CrashSummary, CrashPointers.ExceptionRecord->ExceptionFlags);
|
|
|
|
|
|
|
|
Writef (file, "Windows %s %d.%d Build %d %s\r\n\r\n",
|
|
|
|
verinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ? "9x" : "NT",
|
|
|
|
verinfo.dwMajorVersion, verinfo.dwMinorVersion, verinfo.dwBuildNumber, verinfo.szCSDVersion);
|
|
|
|
|
|
|
|
CONTEXT *ctxt = CrashPointers.ContextRecord;
|
|
|
|
|
|
|
|
if (ctxt->ContextFlags & CONTEXT_SEGMENTS)
|
|
|
|
{
|
|
|
|
Writef (file, "GS=%04x FS=%04x ES=%04x DS=%04x\r\n",
|
|
|
|
ctxt->SegGs, ctxt->SegFs, ctxt->SegEs, ctxt->SegDs);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctxt->ContextFlags & CONTEXT_INTEGER)
|
|
|
|
{
|
2008-04-29 02:43:42 +00:00
|
|
|
#ifndef _M_X64
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\r\nESI=%08x EDI=%08x\r\n",
|
|
|
|
ctxt->Eax, ctxt->Ebx, ctxt->Ecx, ctxt->Edx, ctxt->Esi, ctxt->Edi);
|
2008-04-29 02:43:42 +00:00
|
|
|
#else
|
|
|
|
Writef (file, "RAX=%016I64x RBX=%016I64x RCX=%016I64x\r\n"
|
|
|
|
"RDX=%016I64x RSI=%016I64x RDI=%016I64x\r\n"
|
|
|
|
"RBP=%016I64x R8=%016I64x R9=%016I64x\r\n"
|
|
|
|
"R10=%016I64x R11=%016I64x R12=%016I64x\r\n"
|
|
|
|
"R13=%016I64x R14=%016I64x R15=%016I64x\r\n",
|
|
|
|
ctxt->Rax, ctxt->Rbx, ctxt->Rcx, ctxt->Rdx, ctxt->Rsi, ctxt->Rdi, ctxt->Rbp,
|
|
|
|
ctxt->R8, ctxt->R9, ctxt->R10, ctxt->R11, ctxt->R12, ctxt->R13, ctxt->R14, ctxt->R15);
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctxt->ContextFlags & CONTEXT_CONTROL)
|
|
|
|
{
|
2008-04-29 02:43:42 +00:00
|
|
|
#ifndef _M_X64
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file, "EBP=%08x EIP=%08x ESP=%08x CS=%04x SS=%04x\r\nEFlags=%08x\r\n",
|
|
|
|
ctxt->Ebp, ctxt->Eip, ctxt->Esp, ctxt->SegCs, ctxt->SegSs, ctxt->EFlags);
|
2008-04-29 02:43:42 +00:00
|
|
|
#else
|
|
|
|
Writef (file, "RIP=%016I64x RSP=%016I64x\r\nCS=%04x SS=%04x EFlags=%08x\r\n",
|
|
|
|
ctxt->Rip, ctxt->Rsp, ctxt->SegCs, ctxt->SegSs, ctxt->EFlags);
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
DWORD j;
|
|
|
|
|
|
|
|
for (i = 0, j = 1; (size_t)i < sizeof(eflagsBits)/sizeof(eflagsBits[0]); j <<= 1, ++i)
|
|
|
|
{
|
|
|
|
if (eflagsBits[i][0] != 'x')
|
|
|
|
{
|
|
|
|
Writef (file, " %c%c%c", eflagsBits[i][0], eflagsBits[i][1],
|
|
|
|
ctxt->EFlags & j ? '+' : '-');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Writef (file, "\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctxt->ContextFlags & CONTEXT_FLOATING_POINT)
|
|
|
|
{
|
2008-04-29 02:43:42 +00:00
|
|
|
#ifndef _M_X64
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file,
|
|
|
|
"\r\nFPU State:\r\n ControlWord=%04x StatusWord=%04x TagWord=%04x\r\n"
|
|
|
|
" ErrorOffset=%08x\r\n ErrorSelector=%08x\r\n DataOffset=%08x\r\n DataSelector=%08x\r\n"
|
|
|
|
" Cr0NpxState=%08x\r\n\r\n",
|
|
|
|
(WORD)ctxt->FloatSave.ControlWord, (WORD)ctxt->FloatSave.StatusWord, (WORD)ctxt->FloatSave.TagWord,
|
|
|
|
ctxt->FloatSave.ErrorOffset, ctxt->FloatSave.ErrorSelector, ctxt->FloatSave.DataOffset,
|
|
|
|
ctxt->FloatSave.DataSelector, ctxt->FloatSave.Cr0NpxState);
|
|
|
|
|
|
|
|
for (i = 0; i < 8; ++i)
|
|
|
|
{
|
2009-08-02 03:38:57 +00:00
|
|
|
DWORD d0, d1;
|
|
|
|
memcpy(&d0, &ctxt->FloatSave.RegisterArea[20*i+4], sizeof(DWORD));
|
|
|
|
memcpy(&d1, &ctxt->FloatSave.RegisterArea[20*i], sizeof(DWORD));
|
|
|
|
Writef (file, "MM%d=%08x%08x\r\n", i, d0, d1);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-04-29 02:43:42 +00:00
|
|
|
#else
|
|
|
|
for (i = 0; i < 8; ++i)
|
|
|
|
{
|
|
|
|
Writef (file, "MM%d=%016I64x\r\n", i, ctxt->Legacy[i].Low);
|
|
|
|
}
|
|
|
|
for (i = 0; i < 16; ++i)
|
|
|
|
{
|
|
|
|
Writef (file, "XMM%d=%016I64x%016I64x\r\n", i, ctxt->FltSave.XmmRegisters[i].High, ctxt->FltSave.XmmRegisters[i].Low);
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AddToolHelp (file);
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
#ifdef _M_IX86
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file, "\r\nBytes near EIP:");
|
2008-08-24 04:51:15 +00:00
|
|
|
#else
|
|
|
|
Writef (file, "\r\nBytes near RIP:");
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
DumpBytes (file, (BYTE *)CrashPointers.ExceptionRecord->ExceptionAddress-16);
|
|
|
|
|
|
|
|
if (ctxt->ContextFlags & CONTEXT_CONTROL)
|
|
|
|
{
|
2008-04-29 02:43:42 +00:00
|
|
|
#ifndef _M_X64
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
AddStackInfo (file, (void *)(size_t)CrashPointers.ContextRecord->Esp,
|
2008-08-24 04:51:15 +00:00
|
|
|
CrashPointers.ExceptionRecord->ExceptionCode, ctxt);
|
2008-04-29 02:43:42 +00:00
|
|
|
#else
|
|
|
|
AddStackInfo (file, (void *)CrashPointers.ContextRecord->Rsp,
|
2008-08-24 04:51:15 +00:00
|
|
|
CrashPointers.ExceptionRecord->ExceptionCode, ctxt);
|
2008-04-29 02:43:42 +00:00
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// AddToolHelp
|
|
|
|
//
|
|
|
|
// Adds the information supplied by the tool help functions to the text
|
|
|
|
// report. This includes the list of threads for this process and the
|
|
|
|
// loaded modules.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void AddToolHelp (HANDLE file)
|
|
|
|
{
|
|
|
|
HMODULE kernel = GetModuleHandle ("kernel32.dll");
|
|
|
|
if (kernel == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CREATESNAPSHOT pCreateToolhelp32Snapshot;
|
|
|
|
THREADWALK pThread32First;
|
|
|
|
THREADWALK pThread32Next;
|
|
|
|
MODULEWALK pModule32First;
|
|
|
|
MODULEWALK pModule32Next;
|
|
|
|
|
|
|
|
pCreateToolhelp32Snapshot = (CREATESNAPSHOT)GetProcAddress (kernel, "CreateToolhelp32Snapshot");
|
|
|
|
pThread32First = (THREADWALK)GetProcAddress (kernel, "Thread32First");
|
|
|
|
pThread32Next = (THREADWALK)GetProcAddress (kernel, "Thread32Next");
|
|
|
|
pModule32First = (MODULEWALK)GetProcAddress (kernel, "Module32First");
|
|
|
|
pModule32Next = (MODULEWALK)GetProcAddress (kernel, "Module32Next");
|
|
|
|
|
|
|
|
if (!(pCreateToolhelp32Snapshot && pThread32First && pThread32Next &&
|
|
|
|
pModule32First && pModule32Next))
|
|
|
|
{
|
|
|
|
Writef (file, "\r\nTool Help unavailable\r\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE snapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPMODULE|TH32CS_SNAPTHREAD, 0);
|
|
|
|
if (snapshot == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
Writef (file, "\r\nTool Help snapshot unavailable\r\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
THREADENTRY32 thread = { sizeof(thread) };
|
|
|
|
|
|
|
|
Writef (file, "\r\nRunning threads:\r\n");
|
|
|
|
|
|
|
|
if (pThread32First (snapshot, &thread))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (thread.th32OwnerProcessID == DbgProcessID)
|
|
|
|
{
|
|
|
|
Writef (file, "%08x", thread.th32ThreadID);
|
|
|
|
|
|
|
|
if (thread.th32ThreadID == DbgThreadID)
|
|
|
|
{
|
2008-08-24 04:51:15 +00:00
|
|
|
Writef (file, " at %p*", CrashAddress);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
Writef (file, "\r\n");
|
|
|
|
}
|
|
|
|
} while (pThread32Next (snapshot, &thread));
|
|
|
|
}
|
|
|
|
|
|
|
|
MODULEENTRY32 module = { sizeof(module) };
|
|
|
|
|
|
|
|
Writef (file, "\r\nLoaded modules:\r\n");
|
|
|
|
|
|
|
|
if (pModule32First (snapshot, &module))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2008-08-24 04:51:15 +00:00
|
|
|
Writef (file, "%p - %p %c%s\r\n",
|
2006-02-24 04:48:15 +00:00
|
|
|
module.modBaseAddr, module.modBaseAddr + module.modBaseSize - 1,
|
|
|
|
module.modBaseAddr <= CrashPointers.ExceptionRecord->ExceptionAddress &&
|
|
|
|
module.modBaseAddr + module.modBaseSize > CrashPointers.ExceptionRecord->ExceptionAddress
|
|
|
|
? '*' : ' ',
|
|
|
|
module.szModule);
|
|
|
|
} while (pModule32Next (snapshot, &module));
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle (snapshot);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// AddStackInfo
|
|
|
|
//
|
|
|
|
// Writes a stack dump to the text report.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
static void AddStackInfo (HANDLE file, void *dumpaddress, DWORD code, CONTEXT *ctxt)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
DWORD *addr = (DWORD *)dumpaddress, *jump;
|
2006-02-24 04:48:15 +00:00
|
|
|
DWORD *topOfStack = GetTopOfStack (dumpaddress);
|
|
|
|
BYTE peekb;
|
2008-08-24 04:51:15 +00:00
|
|
|
#ifdef _M_IX86
|
2006-02-24 04:48:15 +00:00
|
|
|
DWORD peekd;
|
2008-08-24 04:51:15 +00:00
|
|
|
#else
|
|
|
|
QWORD peekq;
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
jump = topOfStack;
|
|
|
|
if (code == EXCEPTION_STACK_OVERFLOW)
|
|
|
|
{
|
|
|
|
// If the stack overflowed, only dump the first and last 16KB of it.
|
|
|
|
if (topOfStack - addr > 32768/4)
|
|
|
|
{
|
|
|
|
jump = addr + 16384/4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
StackWalk (file, dumpaddress, topOfStack, jump, ctxt);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
Writef (file, "\r\nStack Contents:\r\n");
|
|
|
|
DWORD *scan;
|
|
|
|
for (scan = addr; scan < topOfStack; scan += 4)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
ptrdiff_t max;
|
|
|
|
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
if (scan == jump)
|
|
|
|
{
|
|
|
|
scan = topOfStack - 16384/4;
|
|
|
|
Writef (file, "\r\n . . . Snip . . .\r\n\r\n");
|
|
|
|
}
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
Writef (file, "%p:", scan);
|
|
|
|
#ifdef _M_IX86
|
2006-02-24 04:48:15 +00:00
|
|
|
if (topOfStack - scan < 4)
|
|
|
|
{
|
|
|
|
max = topOfStack - scan;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < max; ++i)
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
if (!SafeReadMemory (&scan[i], &peekd, 4))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Writef (file, " %08x", peekd);
|
|
|
|
}
|
|
|
|
for (; i < 4; ++i)
|
|
|
|
{
|
|
|
|
Writef (file, " ");
|
|
|
|
}
|
2008-08-24 04:51:15 +00:00
|
|
|
#else
|
|
|
|
if ((QWORD *)topOfStack - (QWORD *)scan < 2)
|
|
|
|
{
|
|
|
|
max = (QWORD *)topOfStack - (QWORD *)scan;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < max; ++i)
|
|
|
|
{
|
|
|
|
if (!SafeReadMemory (&scan[i], &peekq, 8))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Writef (file, " %016x", peekq);
|
|
|
|
}
|
|
|
|
if (i < 2)
|
|
|
|
{
|
|
|
|
Writef (file, " ");
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-24 04:48:15 +00:00
|
|
|
Writef (file, " ");
|
2008-08-30 19:44:19 +00:00
|
|
|
for (i = 0; i < int(max*sizeof(void*)); ++i)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
if (!SafeReadMemory ((BYTE *)scan + i, &peekb, 1))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Writef (file, "%c", peekb >= 0x20 && peekb <= 0x7f ? peekb : '\xb7');
|
|
|
|
}
|
|
|
|
Writef (file, "\r\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
#ifdef _M_IX86
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// StackWalk
|
2008-08-24 04:51:15 +00:00
|
|
|
// Win32 version
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
// Lists a possible call trace for the crashing thread to the text report.
|
|
|
|
// This is not very specific and just lists any pointers into the
|
|
|
|
// main executable region, whether they are part of the real trace or not.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD *jump, CONTEXT *ctxt)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
DWORD *addr = (DWORD *)dumpaddress;
|
|
|
|
|
|
|
|
BYTE *pBaseOfImage = (BYTE *)GetModuleHandle (0);
|
|
|
|
IMAGE_OPTIONAL_HEADER *pHeader = (IMAGE_OPTIONAL_HEADER *)(pBaseOfImage +
|
|
|
|
((IMAGE_DOS_HEADER*)pBaseOfImage)->e_lfanew +
|
|
|
|
sizeof(IMAGE_NT_SIGNATURE) + sizeof(IMAGE_FILE_HEADER));
|
|
|
|
|
|
|
|
DWORD_PTR codeStart = (DWORD_PTR)pBaseOfImage + pHeader->BaseOfCode;
|
|
|
|
DWORD_PTR codeEnd = codeStart + pHeader->SizeOfCode;
|
|
|
|
|
|
|
|
Writef (file, "\r\nPossible call trace:\r\n %08x BOOM", CrashAddress);
|
2008-04-29 02:43:42 +00:00
|
|
|
for (DWORD *scan = addr; scan < topOfStack; ++scan)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
if (scan == jump)
|
|
|
|
{
|
|
|
|
scan = topOfStack - 16384/4;
|
|
|
|
Writef (file, "\r\n\r\n . . . . Snip . . . .\r\n");
|
|
|
|
}
|
|
|
|
|
2008-04-29 02:43:42 +00:00
|
|
|
DWORD_PTR code;
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
if (SafeReadMemory (scan, &code, sizeof(code)) &&
|
2006-02-24 04:48:15 +00:00
|
|
|
code >= codeStart && code < codeEnd)
|
|
|
|
{
|
|
|
|
static const char regNames[][4] =
|
|
|
|
{
|
|
|
|
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
|
|
|
|
};
|
|
|
|
|
|
|
|
// Check if address is after a call statement. Print what was called if it is.
|
|
|
|
const BYTE *bytep = (BYTE *)code;
|
|
|
|
BYTE peekb;
|
|
|
|
|
2009-03-10 23:07:37 +00:00
|
|
|
#define chkbyte(x,m,v) (SafeReadMemory(x, &peekb, 1) && ((peekb & m) == v))
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (chkbyte(bytep - 5, 0xFF, 0xE8) || chkbyte(bytep - 5, 0xFF, 0xE9))
|
|
|
|
{
|
|
|
|
DWORD peekd;
|
2006-06-24 03:47:17 +00:00
|
|
|
if (SafeReadMemory (bytep - 4, &peekd, 4))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
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) &&
|
2006-06-24 03:47:17 +00:00
|
|
|
SafeReadMemory ((LPCVOID)(jumpaddr + 1), &peekd, 4))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
Writef (file," => jmp %p", peekd + jumpaddr + 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Writef (file, "\r\n %p %s ????????", code - 5,
|
|
|
|
peekb == 0xE9 ? "jmp " : "call");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (chkbyte(bytep - 2, 0xFF, 0xFF) && chkbyte(bytep - 1, 0xF7, 0xD0))
|
|
|
|
{
|
|
|
|
Writef (file, "\r\n %p call %s", code - 2, regNames[peekb & 7]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 2; i < 7; ++i)
|
|
|
|
{
|
|
|
|
if (chkbyte(bytep - i, 0xFF, 0xFF) && chkbyte(bytep - i + 1, 070, 020))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= 7)
|
|
|
|
{
|
|
|
|
Writef (file, "\r\n %08x", code);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int mod, rm, basereg = -1, indexreg = -1;
|
|
|
|
int scale = 1, offset = 0;
|
|
|
|
|
|
|
|
Writef (file, "\r\n %08x", bytep - i);
|
|
|
|
bytep -= i - 1;
|
2006-06-24 03:47:17 +00:00
|
|
|
SafeReadMemory (bytep, &peekb, 1);
|
2006-02-24 04:48:15 +00:00
|
|
|
mod = peekb >> 6;
|
|
|
|
rm = peekb & 7;
|
|
|
|
bytep++;
|
|
|
|
|
|
|
|
if (mod == 0 && rm == 5)
|
|
|
|
{
|
|
|
|
mod = 2;
|
|
|
|
}
|
|
|
|
else if (rm == 4)
|
|
|
|
{
|
|
|
|
int index, base;
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
SafeReadMemory (bytep, &peekb, 1);
|
2006-02-24 04:48:15 +00:00
|
|
|
scale = 1 << (peekb >> 6);
|
|
|
|
index = (peekb >> 3) & 7;
|
|
|
|
base = peekb & 7;
|
|
|
|
bytep++;
|
|
|
|
|
|
|
|
if (index != 4)
|
|
|
|
{
|
|
|
|
indexreg = index;
|
|
|
|
}
|
|
|
|
if (base != 5)
|
|
|
|
{
|
|
|
|
basereg = base;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (mod == 0)
|
|
|
|
{
|
|
|
|
mod = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
basereg = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
basereg = rm;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mod == 1)
|
|
|
|
{
|
|
|
|
signed char miniofs;
|
2006-06-24 03:47:17 +00:00
|
|
|
SafeReadMemory (bytep++, &miniofs, 1);
|
2006-02-24 04:48:15 +00:00
|
|
|
offset = miniofs;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
SafeReadMemory (bytep, &offset, 4);
|
2006-02-24 04:48:15 +00:00
|
|
|
bytep += 4;
|
|
|
|
}
|
|
|
|
if ((DWORD_PTR)bytep == code)
|
|
|
|
{
|
|
|
|
Writef (file, " call [", bytep - i + 1);
|
|
|
|
if (basereg >= 0)
|
|
|
|
{
|
|
|
|
Writef (file, "%s", regNames[basereg]);
|
|
|
|
}
|
|
|
|
if (indexreg >= 0)
|
|
|
|
{
|
|
|
|
Writef (file, "%s%s", basereg >= 0 ? "+" : "", regNames[indexreg]);
|
|
|
|
if (scale > 1)
|
|
|
|
{
|
|
|
|
Writef (file, "*%d", scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (offset != 0)
|
|
|
|
{
|
|
|
|
if (indexreg < 0 && basereg < 0)
|
|
|
|
{
|
|
|
|
Writef (file, "%08x", offset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char sign;
|
|
|
|
if (offset < 0)
|
|
|
|
{
|
|
|
|
sign = '-';
|
|
|
|
offset = -offset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sign = '+';
|
|
|
|
}
|
|
|
|
Writef (file, "%c0x%x", sign, offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Writef (file, "]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Writef (file, "\r\n");
|
|
|
|
}
|
|
|
|
|
2008-08-24 04:51:15 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// StackWalk
|
|
|
|
// Win64 version
|
|
|
|
//
|
|
|
|
// Walks the stack for the crashing thread and dumps the trace to the text
|
|
|
|
// report. Unlike the Win32 version, Win64 provides facilities for
|
|
|
|
// doing a 100% exact walk.
|
|
|
|
//
|
|
|
|
// See http://www.nynaeve.net/?p=113 for more information, and
|
|
|
|
// http://www.nynaeve.net/Code/StackWalk64.cpp in particular.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void StackWalk (HANDLE file, void *dumpaddress, DWORD *topOfStack, DWORD *jump, CONTEXT *ctxt)
|
|
|
|
{
|
|
|
|
RTLLOOKUPFUNCTIONENTRY RtlLookupFunctionEntry;
|
|
|
|
HMODULE kernel;
|
|
|
|
CONTEXT context;
|
|
|
|
KNONVOLATILE_CONTEXT_POINTERS nv_context;
|
|
|
|
PRUNTIME_FUNCTION function;
|
|
|
|
PVOID handler_data;
|
|
|
|
ULONG64 establisher_frame;
|
|
|
|
ULONG64 image_base;
|
|
|
|
|
|
|
|
Writef (file, "\r\nCall trace:\r\n rip=%p <- Here it dies.\r\n", CrashAddress);
|
|
|
|
|
|
|
|
kernel = GetModuleHandle("kernel32.dll");
|
|
|
|
if (kernel == NULL || NULL == (RtlLookupFunctionEntry =
|
|
|
|
(RTLLOOKUPFUNCTIONENTRY)GetProcAddress(kernel, "RtlLookupFunctionEntry")))
|
|
|
|
{
|
|
|
|
Writef (file, " Unavailable: Could not get address of RtlLookupFunctionEntry\r\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Get the caller's context
|
|
|
|
context = *ctxt;
|
|
|
|
|
|
|
|
// This unwind loop intentionally skips the first call frame, as it
|
|
|
|
// shall correspond to the call to StackTrace64, which we aren't
|
|
|
|
// interested in.
|
|
|
|
|
|
|
|
for (ULONG frame = 0; ; ++frame)
|
|
|
|
{
|
|
|
|
// Try to look up unwind metadata for the current function.
|
|
|
|
function = RtlLookupFunctionEntry(context.Rip, &image_base, NULL);
|
|
|
|
memset(&nv_context, 0, sizeof(nv_context));
|
|
|
|
if (function == NULL)
|
|
|
|
{
|
|
|
|
// If we don't have a RUNTIME_FUNCTION, then we've encountered
|
|
|
|
// a leaf function. Adjust the stack appropriately.
|
|
|
|
context.Rip = (ULONG64)(*(PULONG64)context.Rsp);
|
|
|
|
context.Rsp += 8;
|
|
|
|
Writef(file, " Leaf function\r\n\r\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Note that there is not a one-to-one correspondance between
|
|
|
|
// runtime functions and source functions. One source function
|
|
|
|
// may be broken into multiple runtime functions. This loop walks
|
|
|
|
// backward from the current runtime function for however many
|
|
|
|
// consecutive runtime functions precede it. There is a slight
|
|
|
|
// chance that this will walk across different source functions.
|
|
|
|
// (Or maybe not, depending on whether or not the compiler
|
|
|
|
// guarantees that there will be empty space between functions;
|
|
|
|
// it looks like VC++ might.) In practice, this seems to work
|
|
|
|
// quite well for identifying the exact address to search for in
|
|
|
|
// a map file to determine the function name.
|
|
|
|
|
|
|
|
PRUNTIME_FUNCTION function2 = function;
|
|
|
|
ULONG64 base = image_base;
|
|
|
|
|
|
|
|
while (function2 != NULL)
|
|
|
|
{
|
|
|
|
Writef(file, " Function range: %p -> %p\r\n",
|
|
|
|
(void *)(base + function2->BeginAddress),
|
|
|
|
(void *)(base + function2->EndAddress));
|
|
|
|
function2 = RtlLookupFunctionEntry(base + function2->BeginAddress - 1, &base, NULL);
|
|
|
|
}
|
|
|
|
Writef(file, "\r\n");
|
|
|
|
|
|
|
|
// Use RtlVirtualUnwind to execute the unwind for us.
|
|
|
|
RtlVirtualUnwind(0/*UNW_FLAG_NHANDLER*/, image_base, context.Rip,
|
|
|
|
function, &context, &handler_data, &establisher_frame,
|
|
|
|
&nv_context);
|
|
|
|
}
|
|
|
|
// If we reach a RIP of zero, this means we've walked off the end of
|
|
|
|
// the call stack and are done.
|
2010-09-01 03:30:18 +00:00
|
|
|
if (context.Rip == 0)
|
2008-08-24 04:51:15 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display the context. Note that we don't bother showing the XMM
|
|
|
|
// context, although we have the nonvolatile portion of it.
|
|
|
|
Writef(file, " FRAME %02d:\r\n rip=%p rsp=%p rbp=%p\r\n",
|
|
|
|
frame, context.Rip, context.Rsp, context.Rbp);
|
|
|
|
Writef(file, " r12=%p r13=%p r14=%p\r\n"
|
|
|
|
" rdi=%p rsi=%p rbx=%p\r\n",
|
|
|
|
context.R12, context.R13, context.R14,
|
|
|
|
context.Rdi, context.Rsi, context.Rbx);
|
|
|
|
|
|
|
|
static const char reg_names[16][4] =
|
|
|
|
{
|
|
|
|
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
|
|
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
|
|
|
|
};
|
|
|
|
|
|
|
|
// If we have stack-based register stores, then display them here.
|
|
|
|
for (int i = 0; i < 16; ++i)
|
|
|
|
{
|
|
|
|
if (nv_context.IntegerContext[i])
|
|
|
|
{
|
|
|
|
Writef(file, " -> '%s' saved on stack at %p (=> %p)\r\n",
|
|
|
|
reg_names[i], nv_context.IntegerContext[i], *nv_context.IntegerContext[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// DumpBytes
|
|
|
|
//
|
|
|
|
// Writes the bytes around EIP to the text report.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void DumpBytes (HANDLE file, BYTE *address)
|
|
|
|
{
|
2008-08-24 04:51:15 +00:00
|
|
|
char line[68*3], *line_p = line;
|
2006-02-24 04:48:15 +00:00
|
|
|
DWORD len;
|
|
|
|
BYTE peek;
|
|
|
|
|
|
|
|
for (int i = 0; i < 16*3; ++i)
|
|
|
|
{
|
|
|
|
if ((i & 15) == 0)
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
line_p += mysnprintf (line_p, countof(line) - (line_p - line), "\r\n%p:", address);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
if (SafeReadMemory (address, &peek, 1))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
line_p += mysnprintf (line_p, countof(line) - (line_p - line), " %02x", *address);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
line_p += mysnprintf (line_p, countof(line) - (line_p - line), " --");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
address++;
|
|
|
|
}
|
|
|
|
*line_p++ = '\r';
|
|
|
|
*line_p++ = '\n';
|
|
|
|
WriteFile (file, line, DWORD(line_p - line), &len, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CreateTempFile
|
|
|
|
//
|
|
|
|
// Creates a new temporary with read/write access. The file will be deleted
|
|
|
|
// automatically when it is closed.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static HANDLE CreateTempFile ()
|
|
|
|
{
|
|
|
|
char temppath[MAX_PATH-13];
|
|
|
|
char tempname[MAX_PATH];
|
|
|
|
if (!GetTempPath (sizeof(temppath), temppath))
|
|
|
|
{
|
|
|
|
temppath[0] = '.';
|
|
|
|
temppath[1] = '\0';
|
|
|
|
}
|
|
|
|
if (!GetTempFileName (temppath, "zdo", 0, tempname))
|
|
|
|
{
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
return CreateFile (tempname, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS,
|
|
|
|
FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE|FILE_FLAG_SEQUENTIAL_SCAN,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// AddFile
|
|
|
|
//
|
|
|
|
// Add another file to be written to the tar.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void AddFile (HANDLE file, const char *filename)
|
|
|
|
{
|
|
|
|
if (NumFiles == MAX_FILES || file == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TarFiles[NumFiles].File = file;
|
|
|
|
TarFiles[NumFiles].Filename = filename;
|
|
|
|
NumFiles++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CloseTarFiles
|
|
|
|
//
|
|
|
|
// Close all files that were previously registerd with AddFile(). They
|
|
|
|
// must still be open.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void CloseTarFiles ()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NumFiles; ++i)
|
|
|
|
{
|
|
|
|
CloseHandle (TarFiles[i].File);
|
|
|
|
}
|
|
|
|
NumFiles = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// WriteBlock
|
|
|
|
//
|
|
|
|
// This is a wrapper around WriteFile. If stream is non-NULL, then the data
|
2006-06-24 03:47:17 +00:00
|
|
|
// is compressed before writing it to the file. outbuf must be 1024 bytes.
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static DWORD WriteBlock (HANDLE file, LPCVOID buffer, DWORD bytes, z_stream *stream, Bytef *outbuf)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (stream == NULL)
|
|
|
|
{
|
|
|
|
WriteFile (file, buffer, bytes, &bytes, NULL);
|
2006-06-24 03:47:17 +00:00
|
|
|
return bytes;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
DWORD wrote = 0;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
stream->next_in = (Bytef *)buffer;
|
|
|
|
stream->avail_in = bytes;
|
|
|
|
|
2006-05-22 01:34:07 +00:00
|
|
|
while (stream->avail_in != 0)
|
|
|
|
{
|
|
|
|
if (stream->avail_out == 0)
|
|
|
|
{
|
|
|
|
stream->next_out = outbuf;
|
2006-06-24 03:47:17 +00:00
|
|
|
stream->avail_out = 1024;
|
|
|
|
wrote += 1024;
|
|
|
|
WriteFile (file, outbuf, 1024, &bytes, NULL);
|
2006-05-22 01:34:07 +00:00
|
|
|
}
|
|
|
|
deflate (stream, Z_NO_FLUSH);
|
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
return wrote;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
2006-06-24 03:47:17 +00:00
|
|
|
// WriteZip
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
2006-06-24 03:48:38 +00:00
|
|
|
// Writes a .zip/pk3 file. A HANDLE to the file is returned. This file is
|
|
|
|
// delete-on-close.
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
// The archive contains all the files previously passed to AddFile(). They
|
2006-06-24 03:48:38 +00:00
|
|
|
// must still be open, because MakeZip() does not open them itself.
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static HANDLE MakeZip ()
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
zip::CentralDirectoryEntry central = { ZIP_CENTRALFILE, { 20, 0 }, { 20, 0 }, };
|
|
|
|
zip::EndOfCentralDirectory dirend = { ZIP_ENDOFDIR, };
|
|
|
|
short dosdate, dostime;
|
2006-02-24 04:48:15 +00:00
|
|
|
time_t now;
|
2006-06-24 03:47:17 +00:00
|
|
|
struct tm *nowtm;
|
|
|
|
int i, numfiles;
|
2006-02-24 04:48:15 +00:00
|
|
|
HANDLE file;
|
2006-06-24 03:47:17 +00:00
|
|
|
DWORD len, dirsize;
|
2006-06-25 01:11:28 +00:00
|
|
|
size_t namelen;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (NumFiles == 0)
|
|
|
|
{
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// Open the zip file.
|
2006-02-24 04:48:15 +00:00
|
|
|
file = CreateTempFile ();
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
time (&now);
|
|
|
|
nowtm = localtime (&now);
|
|
|
|
|
|
|
|
if (nowtm == NULL || nowtm->tm_year < 80)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
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);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// Write out the zip archive, one file at a time
|
|
|
|
for (i = 0; i < NumFiles; ++i)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
AddZipFile (file, &TarFiles[i], dosdate, dostime);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the central directory
|
|
|
|
central.ModTime = dostime;
|
|
|
|
central.ModDate = dosdate;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
dirend.DirectoryOffset = LittleLong(SetFilePointer (file, 0, NULL, FILE_CURRENT));
|
|
|
|
|
|
|
|
for (i = 0, numfiles = 0, dirsize = 0; i < NumFiles; ++i)
|
|
|
|
{
|
2006-02-24 04:48:15 +00:00
|
|
|
// Skip empty files
|
2006-06-24 03:47:17 +00:00
|
|
|
if (TarFiles[i].UncompressedSize == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
numfiles++;
|
|
|
|
if (TarFiles[i].Deflated)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
central.Flags = LittleShort(2);
|
|
|
|
central.Method = LittleShort(8);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
central.Flags = 0;
|
|
|
|
central.Method = 0;
|
|
|
|
}
|
2006-06-25 01:11:28 +00:00
|
|
|
namelen = strlen(TarFiles[i].Filename);
|
|
|
|
central.InternalAttributes = 0;
|
|
|
|
if (namelen > 4 && stricmp(TarFiles[i].Filename - 4, ".txt") == 0)
|
|
|
|
{ // Bit 0 set indicates this is probably a text file. But do any tools use it?
|
|
|
|
central.InternalAttributes = LittleShort(1);
|
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
central.CRC32 = LittleLong(TarFiles[i].CRC32);
|
|
|
|
central.CompressedSize = LittleLong(TarFiles[i].CompressedSize);
|
|
|
|
central.UncompressedSize = LittleLong(TarFiles[i].UncompressedSize);
|
2006-06-25 01:11:28 +00:00
|
|
|
central.NameLength = LittleShort((WORD)namelen);
|
2006-06-24 03:47:17 +00:00
|
|
|
central.LocalHeaderOffset = LittleLong(TarFiles[i].ZipOffset);
|
|
|
|
WriteFile (file, ¢ral, sizeof(central), &len, NULL);
|
2006-06-25 01:11:28 +00:00
|
|
|
WriteFile (file, TarFiles[i].Filename, (DWORD)namelen, &len, NULL);
|
2006-06-27 23:49:45 +00:00
|
|
|
dirsize += DWORD(sizeof(central) + namelen);
|
2006-06-24 03:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
stream.zalloc = Z_NULL;
|
|
|
|
stream.zfree = Z_NULL;
|
|
|
|
err = deflateInit2 (&stream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
|
|
|
|
8, Z_DEFAULT_STRATEGY);
|
|
|
|
gzip = err == Z_OK;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
if (gzip)
|
|
|
|
{
|
|
|
|
local.Method = LittleShort(8);
|
|
|
|
whichfile->Deflated = true;
|
|
|
|
stream.next_out = outbuf;
|
|
|
|
stream.avail_out = sizeof(outbuf);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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; )
|
|
|
|
{
|
|
|
|
len = whichfile->UncompressedSize - k;
|
|
|
|
if (len > 1024)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
len = 1024;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-06-24 03:47:17 +00:00
|
|
|
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);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// Flush the zlib stream buffer.
|
2006-02-24 04:48:15 +00:00
|
|
|
if (gzip)
|
|
|
|
{
|
|
|
|
for (bool done = false;;)
|
|
|
|
{
|
|
|
|
len = sizeof(outbuf) - stream.avail_out;
|
|
|
|
if (len != 0)
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
whichfile->CompressedSize += len;
|
|
|
|
WriteFile (ziphandle, outbuf, len, &wrote, NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
stream.next_out = outbuf;
|
|
|
|
stream.avail_out = sizeof(outbuf);
|
|
|
|
}
|
|
|
|
if (done)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
err = deflate (&stream, Z_FINISH);
|
|
|
|
done = stream.avail_out != 0 || err == Z_STREAM_END;
|
|
|
|
if (err != Z_STREAM_END && err != Z_OK)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
deflateEnd (&stream);
|
|
|
|
}
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
// 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);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// DrawTransparentBitmap
|
|
|
|
//
|
|
|
|
// The replacement for TransparentBlt that does not leak memory under
|
|
|
|
// Windows 98/ME. As seen in the MSKB.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,
|
|
|
|
short yStart, COLORREF cTransparentColor)
|
|
|
|
{
|
|
|
|
BITMAP bm;
|
|
|
|
COLORREF cColor;
|
|
|
|
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
|
|
|
|
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
|
|
|
|
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
|
|
|
|
POINT ptSize;
|
|
|
|
|
|
|
|
hdcTemp = CreateCompatibleDC(hdc);
|
|
|
|
SelectObject(hdcTemp, hBitmap); // Select the bitmap
|
|
|
|
|
|
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
|
|
|
|
ptSize.x = bm.bmWidth; // Get width of bitmap
|
|
|
|
ptSize.y = bm.bmHeight; // Get height of bitmap
|
|
|
|
DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
|
|
|
|
|
|
|
|
// to logical points
|
|
|
|
|
|
|
|
// Create some DCs to hold temporary data.
|
|
|
|
hdcBack = CreateCompatibleDC(hdc);
|
|
|
|
hdcObject = CreateCompatibleDC(hdc);
|
|
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
hdcSave = CreateCompatibleDC(hdc);
|
|
|
|
|
|
|
|
// Create a bitmap for each DC. DCs are required for a number of
|
|
|
|
// GDI functions.
|
|
|
|
|
|
|
|
// Monochrome DC
|
|
|
|
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
|
|
|
|
|
|
|
// Monochrome DC
|
|
|
|
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
|
|
|
|
|
|
|
bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
|
|
|
|
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
|
|
|
|
|
|
|
|
// Each DC must select a bitmap object to store pixel data.
|
|
|
|
bmBackOld = (HBITMAP)SelectObject(hdcBack, bmAndBack);
|
|
|
|
bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
|
|
|
|
bmMemOld = (HBITMAP)SelectObject(hdcMem, bmAndMem);
|
|
|
|
bmSaveOld = (HBITMAP)SelectObject(hdcSave, bmSave);
|
|
|
|
|
|
|
|
// Set proper mapping mode.
|
|
|
|
SetMapMode(hdcTemp, GetMapMode(hdc));
|
|
|
|
|
|
|
|
// Save the bitmap sent here, because it will be overwritten.
|
|
|
|
BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
|
|
|
|
|
|
|
|
// Set the background color of the source DC to the color.
|
|
|
|
// contained in the parts of the bitmap that should be transparent
|
|
|
|
cColor = SetBkColor(hdcTemp, cTransparentColor);
|
|
|
|
|
|
|
|
// Create the object mask for the bitmap by performing a BitBlt
|
|
|
|
// from the source bitmap to a monochrome bitmap.
|
|
|
|
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
|
|
|
|
SRCCOPY);
|
|
|
|
|
|
|
|
// Set the background color of the source DC back to the original
|
|
|
|
// color.
|
|
|
|
SetBkColor(hdcTemp, cColor);
|
|
|
|
|
|
|
|
// Create the inverse of the object mask.
|
|
|
|
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
|
|
|
|
NOTSRCCOPY);
|
|
|
|
|
|
|
|
// Copy the background of the main DC to the destination.
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,
|
|
|
|
SRCCOPY);
|
|
|
|
|
|
|
|
// Mask out the places where the bitmap will be placed.
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
|
|
|
|
|
|
|
|
// Mask out the transparent colored pixels on the bitmap.
|
|
|
|
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
|
|
|
|
|
|
|
|
// XOR the bitmap with the background on the destination DC.
|
|
|
|
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
|
|
|
|
|
|
|
// Copy the destination to the screen.
|
|
|
|
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,
|
|
|
|
SRCCOPY);
|
|
|
|
|
|
|
|
// Place the original bitmap back into the bitmap sent here.
|
|
|
|
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
|
|
|
|
|
|
|
|
// Delete the memory bitmaps.
|
|
|
|
DeleteObject(SelectObject(hdcBack, bmBackOld));
|
|
|
|
DeleteObject(SelectObject(hdcObject, bmObjectOld));
|
|
|
|
DeleteObject(SelectObject(hdcMem, bmMemOld));
|
|
|
|
DeleteObject(SelectObject(hdcSave, bmSaveOld));
|
|
|
|
|
|
|
|
// Delete the memory DCs.
|
|
|
|
DeleteDC(hdcMem);
|
|
|
|
DeleteDC(hdcBack);
|
|
|
|
DeleteDC(hdcObject);
|
|
|
|
DeleteDC(hdcSave);
|
|
|
|
DeleteDC(hdcTemp);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// TransparentStaticProc
|
|
|
|
//
|
|
|
|
// A special window procedure for the static control displaying the dying
|
|
|
|
// Doom Guy. It draws the bitmap with magenta as transparent. I could have
|
|
|
|
// made it an owner-draw control instead, but then I wouldn't get any of
|
|
|
|
// the standard bitmap graphic handling (like automatic sizing).
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static LRESULT CALLBACK TransparentStaticProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
PAINTSTRUCT paint;
|
|
|
|
HDC dc;
|
|
|
|
|
|
|
|
if (uMsg == WM_PAINT)
|
|
|
|
{
|
|
|
|
if (GetUpdateRect (hWnd, &rect, FALSE))
|
|
|
|
{
|
|
|
|
dc = BeginPaint (hWnd, &paint);
|
|
|
|
if (dc != NULL)
|
|
|
|
{
|
|
|
|
HBITMAP bitmap = (HBITMAP)SendMessage (hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0);
|
|
|
|
if (bitmap != NULL)
|
|
|
|
{
|
|
|
|
DrawTransparentBitmap (dc, bitmap, 0, 0, RGB(255,0,255));
|
|
|
|
}
|
|
|
|
EndPaint (hWnd, &paint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return CallWindowProc (StdStaticProc, hWnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HMODULE WinHlp32;
|
|
|
|
static char *UserSummary;
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// AddDescriptionText
|
|
|
|
//
|
|
|
|
// Adds a file with the contents of the specified edit control to a new
|
|
|
|
// file in the tarball. The control's user data is used to keep track of
|
|
|
|
// the file handle for the created file, so you can call this more than
|
|
|
|
// once and it will only open the file the first time.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void AddDescriptionText (HWND edit)
|
|
|
|
{
|
|
|
|
DWORD textlen;
|
|
|
|
|
|
|
|
textlen = (DWORD)SendMessage (edit, WM_GETTEXTLENGTH, 0, 0) + 1;
|
|
|
|
if (textlen > 1)
|
|
|
|
{
|
|
|
|
UserSummary = (char *)HeapAlloc (GetProcessHeap(), 0, textlen);
|
|
|
|
if (UserSummary != NULL)
|
|
|
|
{
|
|
|
|
textlen = (DWORD)SendMessage (edit, WM_GETTEXT, textlen, (LPARAM)UserSummary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// OverviewDlgProc
|
|
|
|
//
|
|
|
|
// The DialogProc for the crash overview page.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static INT_PTR CALLBACK OverviewDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
CHARFORMAT charFormat;
|
|
|
|
HWND edit;
|
|
|
|
ENLINK *link;
|
|
|
|
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
if (pEnableThemeDialogTexture != NULL)
|
|
|
|
{
|
|
|
|
pEnableThemeDialogTexture (hDlg, ETDT_ENABLETAB);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the header at the top of the page.
|
|
|
|
edit = GetDlgItem (hDlg, IDC_CRASHHEADER);
|
2006-06-24 08:26:21 +00:00
|
|
|
SendMessage (edit, WM_SETTEXT, 0, (LPARAM)GAMENAME" has encountered a problem and needs to close.\n"
|
2006-02-24 04:48:15 +00:00
|
|
|
"We are sorry for the inconvenience.");
|
|
|
|
|
|
|
|
// Setup a bold version of the standard dialog font and make the header bold.
|
|
|
|
charFormat.cbSize = sizeof(charFormat);
|
|
|
|
SendMessage (edit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&charFormat);
|
|
|
|
charFormat.dwEffects = CFE_BOLD;
|
|
|
|
SendMessage (edit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&charFormat);
|
|
|
|
|
|
|
|
// Setup the drawing routine for the dying guy's bitmap.
|
|
|
|
edit = GetDlgItem (hDlg, IDC_DEADGUYVIEWER);
|
|
|
|
StdStaticProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr (edit, GWLP_WNDPROC, (WLONG_PTR)(LONG_PTR)TransparentStaticProc);
|
|
|
|
|
|
|
|
// Fill in all the text just below the heading.
|
|
|
|
edit = GetDlgItem (hDlg, IDC_PLEASETELLUS);
|
|
|
|
SendMessage (edit, EM_AUTOURLDETECT, TRUE, 0);
|
|
|
|
SendMessage (edit, WM_SETTEXT, 0, (LPARAM)"Please tell us about this problem.\n"
|
|
|
|
"The information will NOT be sent to Microsoft.\n\n"
|
2006-06-24 08:26:21 +00:00
|
|
|
"An error report has been created that you can submit to help improve "GAMENAME". "
|
|
|
|
"You can either save it to disk and make a report in the bugs forum at "FORUM_URL", "
|
2006-02-24 04:48:15 +00:00
|
|
|
"or you can send it directly without letting other people know about it.");
|
|
|
|
SendMessage (edit, EM_SETSEL, 0, 81);
|
|
|
|
SendMessage (edit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
|
|
|
|
SendMessage (edit, EM_SETEVENTMASK, 0, ENM_LINK);
|
|
|
|
|
|
|
|
// Assign a default invalid file handle to the user's edit control.
|
|
|
|
edit = GetDlgItem (hDlg, IDC_CRASHINFO);
|
|
|
|
SetWindowLongPtr (edit, GWLP_USERDATA, (LONG_PTR)INVALID_HANDLE_VALUE);
|
|
|
|
|
|
|
|
// Fill in the summary text at the bottom of the page.
|
|
|
|
edit = GetDlgItem (hDlg, IDC_CRASHSUMMARY);
|
|
|
|
SendMessage (edit, WM_SETTEXT, 0, (LPARAM)CrashSummary);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case WM_NOTIFY:
|
|
|
|
// When the link in the "please tell us" edit control is clicked, open
|
|
|
|
// the bugs forum in a browser window. ShellExecute is used to do this,
|
|
|
|
// so the default browser, whatever it may be, will open it.
|
|
|
|
link = (ENLINK *)lParam;
|
|
|
|
if (link->nmhdr.idFrom == IDC_PLEASETELLUS && link->nmhdr.code == EN_LINK)
|
|
|
|
{
|
|
|
|
if (link->msg == WM_LBUTTONDOWN)
|
|
|
|
{
|
|
|
|
ShellExecute (NULL, "open", BUGS_FORUM_URL, NULL, NULL, 0);
|
|
|
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, 1);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
// When this pane is destroyed, extract the user's summary.
|
|
|
|
AddDescriptionText (GetDlgItem (hDlg, IDC_CRASHINFO));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CrashDlgProc
|
|
|
|
//
|
|
|
|
// The DialogProc for the main crash dialog.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static INT_PTR CALLBACK CrashDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2007-03-29 01:03:50 +00:00
|
|
|
static CHAR overview[] = "Overview";
|
|
|
|
static CHAR details[] = "Details";
|
2006-02-24 04:48:15 +00:00
|
|
|
HWND edit;
|
|
|
|
TCITEM tcitem;
|
|
|
|
RECT tabrect, tcrect;
|
|
|
|
LPNMHDR nmhdr;
|
|
|
|
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
// Set up the tab control
|
|
|
|
tcitem.mask = TCIF_TEXT | TCIF_PARAM;
|
|
|
|
edit = GetDlgItem (hDlg, IDC_CRASHTAB);
|
|
|
|
|
|
|
|
GetWindowRect (edit, &tcrect);
|
|
|
|
ScreenToClient (hDlg, (LPPOINT)&tcrect.left);
|
|
|
|
ScreenToClient (hDlg, (LPPOINT)&tcrect.right);
|
|
|
|
|
|
|
|
// There are two tabs: Overview and Details. Each pane is created from a
|
|
|
|
// dialog template, and the resultant window is stored as the lParam for
|
|
|
|
// the corresponding tab.
|
2007-03-29 01:03:50 +00:00
|
|
|
tcitem.pszText = overview;
|
2006-02-24 04:48:15 +00:00
|
|
|
tcitem.lParam = (LPARAM)CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_CRASHOVERVIEW), hDlg, OverviewDlgProc, (LPARAM)edit);
|
|
|
|
TabCtrl_InsertItem (edit, 0, &tcitem);
|
|
|
|
TabCtrl_GetItemRect (edit, 0, &tabrect);
|
|
|
|
SetWindowPos ((HWND)tcitem.lParam, HWND_TOP, tcrect.left + 3, tcrect.top + tabrect.bottom + 3,
|
|
|
|
tcrect.right - tcrect.left - 8, tcrect.bottom - tcrect.top - tabrect.bottom - 8, 0);
|
|
|
|
|
2007-03-29 01:03:50 +00:00
|
|
|
tcitem.pszText = details;
|
Note: I have not tried compiling these recent changes under Linux. I wouldn't
be surprised if it doesn't work.
- Reorganized the network startup loops so now they are event driven. There is
a single function that gets called to drive it, and it uses callbacks to
perform the different stages of the synchronization. This lets me have a nice,
responsive abort button instead of the previous unannounced hit-escape-to-
abort behavior, and I think the rearranged code is slightly easier to
understand too.
- Increased the number of bytes for version info during D_ArbitrateNetStart(),
in preparation for the day when NETGAMEVERSION requires more than one byte.
- I noticed an issue with Vista RC1 and the new fatal error setup. Even after
releasing a DirectDraw or Direct3D interface, the DWM can still use the
last image drawn using them when it composites the window. It doesn't always
do it but it does often enough that it is a real problem. At this point, I
don't know if it's a problem with the release version of Vista or not.
After messing around, I discovered the problem was caused by ~Win32Video()
hiding the window and then having it immediately shown soon after. The DWM
kept an image of the window to do the transition effect with, and then when
it didn't get a chance to do the transition, it didn't properly forget about
its saved image and kept plastering it on top of everything else
underneath.
- Added a network synchronization panel to the window during netgame startup.
- Fixed: PClass::CreateDerivedClass() must initialize StateList to NULL.
Otherwise, classic DECORATE definitions generate a big, fat crash.
- Resurrected the R_Init progress bar, now as a standard Windows control.
- Removed the sound failure dialog. The FMOD setup already defaulted to no
sound if initialization failed, so this only applies when snd_output is set
to "alternate" which now also falls back to no sound. In addition, it wasn't
working right, and I didn't feel like fixing it for the probably 0% of users
it affected.
- Fixed: The edit control used for logging output added text in reverse order
on Win9x.
- Went back to the roots and made graphics initialization one of the last
things to happen during setup. Now the startup text is visible again. More
importantly, the main window is no longer created invisible, which seems
to cause trouble with it not always appearing in the taskbar. The fatal
error dialog is now also embedded in the main window instead of being a
separate modal dialog, so you can play with the log window to see any
problems that might be reported there.
Rather than completely restoring the original startup order, I tried to
keep things as close to the way they were with early graphics startup. In
particular, V_Init() now creates a dummy screen so that things that need
screen dimensions can get them. It gets replaced by the real screen later
in I_InitGraphics(). Will need to check this under Linux to make sure it
didn't cause any problems there.
- Removed the following stubs that just called functions in Video:
- I_StartModeIterator()
- I_NextMode()
- I_DisplayType()
I_FullscreenChanged() was also removed, and a new fullscreen parameter
was added to IVideo::StartModeIterator(), since that's all it controlled.
- Renamed I_InitHardware() back to I_InitGraphics(), since that's all it's
initialized post-1.22.
SVN r416 (trunk)
2006-12-19 04:09:10 +00:00
|
|
|
tcitem.lParam = (LPARAM)CreateDialogParam (g_hInst, MAKEINTRESOURCE(IDD_CRASHDETAILS), hDlg, DetailsDlgProc, (LPARAM)edit);
|
2006-02-24 04:48:15 +00:00
|
|
|
TabCtrl_InsertItem (edit, 1, &tcitem);
|
|
|
|
SetWindowPos ((HWND)tcitem.lParam, HWND_TOP, tcrect.left + 3, tcrect.top + tabrect.bottom + 3,
|
|
|
|
tcrect.right - tcrect.left - 8, tcrect.bottom - tcrect.top - tabrect.bottom - 8, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_NOTIFY:
|
|
|
|
nmhdr = (LPNMHDR)lParam;
|
|
|
|
if (nmhdr->idFrom == IDC_CRASHTAB)
|
|
|
|
{
|
|
|
|
int i = TabCtrl_GetCurSel (nmhdr->hwndFrom);
|
|
|
|
tcitem.mask = TCIF_PARAM;
|
|
|
|
TabCtrl_GetItem (nmhdr->hwndFrom, i, &tcitem);
|
|
|
|
edit = (HWND)tcitem.lParam;
|
|
|
|
|
|
|
|
// TCN_SELCHANGING is sent just before the selected tab changes.
|
|
|
|
// TCN_SELCHANGE is sent just after the selected tab changes.
|
|
|
|
// So, when TCN_SELCHANGING is received hide the pane for the
|
|
|
|
// selected tab, and when TCN_SELCHANGE is received, show the pane
|
|
|
|
// for the selected tab.
|
|
|
|
if (nmhdr->code == TCN_SELCHANGING)
|
|
|
|
{
|
|
|
|
ShowWindow (edit, SW_HIDE);
|
|
|
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (nmhdr->code == TCN_SELCHANGE)
|
|
|
|
{
|
|
|
|
ShowWindow (edit, SW_SHOW);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
|
|
{
|
|
|
|
EndDialog (hDlg, LOWORD(wParam));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// DetailsDlgProc
|
|
|
|
//
|
|
|
|
// The dialog procedure for when the user wants to examine the files
|
|
|
|
// in the report.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
HWND ctrl;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
if (pEnableThemeDialogTexture != NULL)
|
|
|
|
{
|
|
|
|
pEnableThemeDialogTexture (hDlg, ETDT_ENABLETAB);
|
|
|
|
}
|
|
|
|
|
2010-03-04 02:17:34 +00:00
|
|
|
// Set up the file contents display: No undos. The control's
|
|
|
|
// userdata stores the index of the file currently displayed.
|
2006-02-24 04:48:15 +00:00
|
|
|
ctrl = GetDlgItem (hDlg, IDC_CRASHFILECONTENTS);
|
|
|
|
SendMessage (ctrl, EM_SETUNDOLIMIT, 0, 0);
|
|
|
|
SetWindowLongPtr (ctrl, GWLP_USERDATA, -1);
|
|
|
|
SetEditControl (ctrl, GetDlgItem(hDlg, IDC_CRASHFILESIZE), 0);
|
|
|
|
SendMessage (ctrl, LB_SETCURSEL, 0, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SHOWWINDOW:
|
|
|
|
// When showing this pane, refresh the list of packaged files, and
|
|
|
|
// update the contents display as necessary.
|
|
|
|
if (wParam == TRUE)
|
|
|
|
{
|
|
|
|
ctrl = GetDlgItem (hDlg, IDC_CRASHFILES);
|
|
|
|
j = (int)SendMessage (ctrl, LB_GETCURSEL, 0, 0);
|
|
|
|
SendMessage (ctrl, LB_RESETCONTENT, 0, 0);
|
|
|
|
for (i = 0; i < NumFiles; ++i)
|
|
|
|
{
|
|
|
|
SendMessage (ctrl, LB_ADDSTRING, 0, (LPARAM)TarFiles[i].Filename);
|
|
|
|
}
|
|
|
|
if (j == LB_ERR || j >= i) j = 0;
|
|
|
|
SendMessage (ctrl, LB_SETCURSEL, j, 0);
|
|
|
|
|
|
|
|
ctrl = GetDlgItem (hDlg, IDC_CRASHFILECONTENTS);
|
|
|
|
if (j > 2) SetWindowLongPtr (ctrl, GWLP_USERDATA, -1);
|
|
|
|
SetEditControl (ctrl, GetDlgItem(hDlg, IDC_CRASHFILESIZE), j);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
// Selecting a different file makes the contents display update.
|
|
|
|
if (HIWORD(wParam) == LBN_SELCHANGE)
|
|
|
|
{
|
|
|
|
i = (int)SendMessage ((HWND)lParam, LB_GETCURSEL, 0, 0);
|
|
|
|
if (i != LB_ERR)
|
|
|
|
{
|
|
|
|
// Update the contents control for this file
|
|
|
|
SetEditControl (GetDlgItem (hDlg, IDC_CRASHFILECONTENTS),
|
|
|
|
GetDlgItem (hDlg, IDC_CRASHFILESIZE), i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// StreamEditText
|
|
|
|
//
|
|
|
|
// The callback function to stream a text file into a rich edit control.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static DWORD CALLBACK StreamEditText (DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
|
|
|
|
{
|
|
|
|
DWORD wrote;
|
|
|
|
ReadFile ((HANDLE)cookie, buffer, cb, &wrote, NULL);
|
|
|
|
*pcb = wrote;
|
|
|
|
return wrote == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// StreamEditBinary
|
|
|
|
//
|
|
|
|
// The callback function to stream a binary file into a rich edit control.
|
|
|
|
// The binary file is converted to a RTF hex dump so that the different
|
|
|
|
// columns can be color-coded.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
struct BinStreamInfo
|
|
|
|
{
|
|
|
|
int Stage;
|
|
|
|
HANDLE File;
|
|
|
|
DWORD Pointer;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DWORD CALLBACK StreamEditBinary (DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb)
|
|
|
|
{
|
|
|
|
BinStreamInfo *info = (BinStreamInfo *)cookie;
|
|
|
|
BYTE buf16[16];
|
|
|
|
DWORD read, i;
|
|
|
|
char *buff_p = (char *)buffer;
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
char *buff_end = (char *)buffer + cb;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
repeat:
|
|
|
|
switch (info->Stage)
|
|
|
|
{
|
|
|
|
case 0: // Write prologue
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "{\\rtf1\\ansi\\deff0"
|
2006-02-24 04:48:15 +00:00
|
|
|
"{\\colortbl ;\\red0\\green0\\blue80;\\red0\\green0\\blue0;\\red80\\green0\\blue80;}"
|
|
|
|
"\\viewkind4\\pard");
|
|
|
|
info->Stage++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // Write body
|
|
|
|
while (cb - ((LPBYTE)buff_p - buffer) > 150)
|
|
|
|
{
|
|
|
|
ReadFile (info->File, buf16, 16, &read, NULL);
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
if (read == 0 || info->Pointer >= 65536)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
info->Stage = read == 0 ? 2 : 3;
|
2006-02-24 04:48:15 +00:00
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
char *linestart = buff_p;
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "\\cf1 %08lx:\\cf2 ", info->Pointer);
|
2006-02-24 04:48:15 +00:00
|
|
|
info->Pointer += read;
|
|
|
|
|
|
|
|
for (i = 0; i < read;)
|
|
|
|
{
|
|
|
|
if (i <= read - 4)
|
|
|
|
{
|
2009-08-02 03:38:57 +00:00
|
|
|
DWORD d;
|
|
|
|
memcpy(&d, &buf16[i], sizeof(d));
|
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, " %08lx", d);
|
2006-02-24 04:48:15 +00:00
|
|
|
i += 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, " %02x", buf16[i]);
|
2006-02-24 04:48:15 +00:00
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (buff_p - linestart < 57)
|
|
|
|
{
|
|
|
|
*buff_p++ = ' ';
|
|
|
|
}
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "\\cf3 ");
|
2006-02-24 04:48:15 +00:00
|
|
|
for (i = 0; i < read; ++i)
|
|
|
|
{
|
|
|
|
BYTE code = buf16[i];
|
|
|
|
if (code < 0x20 || code > 0x7f) code = 0xB7;
|
|
|
|
if (code == '\\' || code == '{' || code == '}') *buff_p++ = '\\';
|
|
|
|
*buff_p++ = code;
|
|
|
|
}
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "\\par\r\n");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: // Write epilogue
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "\\cf0 }");
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
info->Stage = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // Write epilogue for truncated file
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
buff_p += mysnprintf (buff_p, buff_end - buff_p, "--- Rest of file truncated ---\\cf0 }");
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
info->Stage = 4;
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
|
- Added some hackery at the start of MouseRead_Win32() that prevents it from
yanking the mouse around if they keys haven't been read yet to combat the
same situation that causes the keyboard to return DIERR_NOTACQUIRED in
KeyRead(): The window is sort of in focus and sort of not. User.dll
considers it to be focused and it's drawn as such, but another focused
window is on top of it, and DirectInput doesn't see it as focused.
- Fixed: KeyRead() should handle DIERR_NOTACQUIRED errors the same way it
handles DIERR_INPUTLOST errors. This can happen if our window had the
focus stolen away from it before we tried to acquire the keyboard in
DI_Init2(). Strangely, MouseRead_DI() already did this.
- When a stack overflow occurs, report.txt now only includes the first and
last 16KB of the stack to make it more manageable.
- Limited StreamEditBinary() to the first 64KB of the file to keep it from
taking too long on large dumps.
- And now I know why gathering crash information in the same process that
crashed can be bad: Stack overflows. You get one spare page to play with
when the stack overflows. MiniDumpWriteDump() needs more than that and
causes an access violation when it runs out of leftover stack, silently
terminating the application. Windows XP x64 offers SetThreadStackGuarantee()
to increase this, but that isn't available on anything older, including
32-bit XP. To get around this, a new thread is created to write the mini
dump when the stack overflows.
- Changed A_Burnination() to be closer to Strife's.
- Fixed: When playing back demos, DoAddBot() can be called without an
associated call to SpawnBot(). So if the bot can't spawn, botnum can
go negative, which will cause problems later in DCajunMaster::Main()
when it sees that wanted_botnum (0) is higher than botnum (-1).
- Fixed: Stopping demo recording in multiplayer games should not abruptly
drop the recorder out of the game without notifying the other players.
In fact, there's no reason why it should drop them out of multiplayer at
all.
- Fixed: Earthquakes were unreliable in multiplayer games because
P_PredictPlayer() did not preserve the player's xviewshift.
- Fixed: PlayerIsGone() needs to stop any scripts that belong to the player
who left, in addition to executing disconnect scripts.
- Fixed: APlayerPawn::AddInventory() should also check for a NULL player->mo
in case the player left but somebody still has a reference to their actor.
- Fixed: DDrawFB::PaintToWindow() should simulate proper unlocking behavior
and set Buffer to NULL.
- Improved feedback for network game initialization with the console ticker.
- Moved i_net.cpp and i_net.h out of sdl/ and win32/ and into the main source
directory. They are identical, so keeping two copies of them is bad.
- Fixed: (At least with Creative's driver's,) EAX settings are global and not
per-application. So if you play a multiplayer ZDoom game on one computer
(or even another EAX-using application), ZDoom needs to restore the
environment when it regains focus.
- Maybe fixed: (See http://forum.zdoom.org/potato.php?t=10689) Apparently,
PacketGet can receive ECONNRESET from nodes that aren't in the game. It
should be safe to just ignore these packets.
- Fixed: PlayerIsGone() should set the gone player's camera to NULL in case
the player who left was player 0. This is because if a remaining player
receives a "recoverable" error, they will become player 0. Once that happens,
they game will try to update sounds through their camera and crash in
FMODSoundRenderer::UpdateListener() because the zones array is now NULL.
G_NewInit() should also clear all the player structures.
SVN r233 (trunk)
2006-06-30 02:13:26 +00:00
|
|
|
case 4: // We're done
|
2006-02-24 04:48:15 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pcb = (LONG)((LPBYTE)buff_p - buffer);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// SetEditControl
|
|
|
|
//
|
|
|
|
// Fills the edit control with the contents of the chosen file.
|
|
|
|
// If the filename ends with ".txt" the file is assumed to be text.
|
|
|
|
// Otherwise it is treated as binary, and you get a hex dump.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void SetEditControl (HWND edit, HWND sizedisplay, int filenum)
|
|
|
|
{
|
|
|
|
char sizebuf[32];
|
|
|
|
EDITSTREAM stream;
|
|
|
|
DWORD size;
|
|
|
|
POINT pt = { 0, 0 };
|
2010-03-04 02:17:34 +00:00
|
|
|
const char *rtf = NULL;
|
|
|
|
HGDIOBJ font;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Don't refresh the control if it's already showing the file we want.
|
|
|
|
if (GetWindowLongPtr (edit, GWLP_USERDATA) == filenum)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = GetFileSize (TarFiles[filenum].File, NULL);
|
|
|
|
if (size < 1024)
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (sizebuf, countof(sizebuf), "(%lu bytes)", size);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (sizebuf, countof(sizebuf), "(%lu KB)", size/1024);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
SetWindowText (sizedisplay, sizebuf);
|
|
|
|
|
|
|
|
SetWindowLongPtr (edit, GWLP_USERDATA, filenum);
|
|
|
|
|
|
|
|
SetFilePointer (TarFiles[filenum].File, 0, NULL, FILE_BEGIN);
|
|
|
|
SendMessage (edit, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
|
|
|
|
|
2010-03-04 02:17:34 +00:00
|
|
|
// Set the font now, in case log.rtf was previously viewed, because
|
|
|
|
// that file changes it.
|
|
|
|
font = GetStockObject (ANSI_FIXED_FONT);
|
|
|
|
if (font != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
SendMessage (edit, WM_SETFONT, (WPARAM)font, FALSE);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
// Text files are streamed in as-is.
|
|
|
|
// Binary files are streamed in as color-coded hex dumps.
|
|
|
|
stream.dwError = 0;
|
2010-03-04 02:17:34 +00:00
|
|
|
if (strstr (TarFiles[filenum].Filename, ".txt") != NULL ||
|
|
|
|
(rtf = strstr (TarFiles[filenum].Filename, ".rtf")) != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
CHARFORMAT beBlack;
|
|
|
|
|
|
|
|
beBlack.cbSize = sizeof(beBlack);
|
|
|
|
beBlack.dwMask = CFM_COLOR;
|
|
|
|
beBlack.dwEffects = 0;
|
|
|
|
beBlack.crTextColor = RGB(0,0,0);
|
|
|
|
SendMessage (edit, EM_SETCHARFORMAT, 0, (LPARAM)&beBlack);
|
|
|
|
stream.dwCookie = (DWORD_PTR)TarFiles[filenum].File;
|
|
|
|
stream.pfnCallback = StreamEditText;
|
2010-03-04 02:17:34 +00:00
|
|
|
SendMessage (edit, EM_STREAMIN, rtf ? SF_RTF : SF_TEXT | SF_USECODEPAGE | (1252 << 16), (LPARAM)&stream);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BinStreamInfo info = { 0, TarFiles[filenum].File, 0 };
|
|
|
|
stream.dwCookie = (DWORD_PTR)&info;
|
|
|
|
stream.pfnCallback = StreamEditBinary;
|
|
|
|
SendMessage (edit, EM_EXLIMITTEXT, 0, GetFileSize(TarFiles[filenum].File, NULL)*7);
|
|
|
|
SendMessage (edit, EM_STREAMIN, SF_RTF, (LPARAM)&stream);
|
|
|
|
}
|
|
|
|
SendMessage (edit, EM_SETSEL, (WPARAM)-1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 // Server-side support is not done yet
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// GetHeader
|
|
|
|
//
|
|
|
|
// Receives the HTTP header from a socket, up to and including the empty
|
|
|
|
// line that terminates the header.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static char *GetHeader (SOCKET sock)
|
|
|
|
{
|
|
|
|
DWORD spaceHave = 0, spaceAt = 0;
|
|
|
|
char *space = NULL;
|
|
|
|
char inchar;
|
|
|
|
int got;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
// Get one character
|
|
|
|
got = recv (sock, &inchar, 1, 0);
|
|
|
|
if (got != 1)
|
|
|
|
{
|
|
|
|
error:
|
|
|
|
if (space != NULL) HeapFree (GetProcessHeap(), 0, space);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// Append it to the header we have so far
|
|
|
|
if (space == NULL)
|
|
|
|
{
|
|
|
|
spaceHave = 256;
|
|
|
|
space = (char *)HeapAlloc (GetProcessHeap(), 0, 256);
|
|
|
|
}
|
|
|
|
else if (spaceAt == spaceHave-1)
|
|
|
|
{
|
|
|
|
spaceHave += 256;
|
|
|
|
space = (char *)HeapReAlloc (GetProcessHeap(), 0, space, spaceHave);
|
|
|
|
}
|
|
|
|
switch (spaceAt)
|
|
|
|
{
|
|
|
|
case 0: if (inchar != 'H') goto error; break;
|
|
|
|
case 1: if (inchar != 'T') goto error; break;
|
|
|
|
case 2: if (inchar != 'T') goto error; break;
|
|
|
|
case 3: if (inchar != 'P') goto error; break;
|
|
|
|
case 4: if (inchar != '/') goto error; break;
|
|
|
|
}
|
|
|
|
space[spaceAt++] = inchar;
|
|
|
|
if (inchar == '\n' && space[spaceAt-2] == '\r' && space[spaceAt-3] == '\n' && space[spaceAt-4] == '\r')
|
|
|
|
{ // The header is complete
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
space[spaceAt++] = '\0';
|
|
|
|
if (spaceAt < 12) goto error;
|
|
|
|
return space;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// UploadFail
|
|
|
|
//
|
|
|
|
// Stuffs some text into the status control to indicate what went wrong.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void UploadFail (HWND hDlg, const char *message, int reason)
|
|
|
|
{
|
|
|
|
char buff[512];
|
|
|
|
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (buff, countof(buff), "%s: %d", message, reason);
|
2006-02-24 04:48:15 +00:00
|
|
|
SetWindowText (GetDlgItem (hDlg, IDC_BOINGSTATUS), buff);
|
|
|
|
|
|
|
|
if (reason >= 10000 && reason <= 11999)
|
|
|
|
{
|
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL,
|
|
|
|
GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(LPTSTR)&lpMsgBuf,
|
|
|
|
0,
|
|
|
|
NULL))
|
|
|
|
{
|
|
|
|
SetWindowText (GetDlgItem (hDlg, IDC_BOINGEDIT), (LPCSTR)lpMsgBuf);
|
|
|
|
LocalFree (lpMsgBuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// GetChunkLen
|
|
|
|
//
|
|
|
|
// Returns the chunk length for a HTTP response using the chunked
|
|
|
|
// transfer-encoding.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static int GetChunkLen (SOCKET sock)
|
|
|
|
{
|
|
|
|
char crlf[2] = { '\r', '\n' };
|
|
|
|
int len = 0;
|
|
|
|
int stage = 0;
|
|
|
|
char inchar;
|
|
|
|
|
|
|
|
while (recv (sock, &inchar, 1, 0) == 1)
|
|
|
|
{
|
|
|
|
switch (stage)
|
|
|
|
{
|
|
|
|
case 0: // Checking for CRLF from the previous chunk
|
|
|
|
case 1:
|
|
|
|
if (inchar == crlf[stage]) { stage++; break; }
|
|
|
|
else stage = 2;
|
|
|
|
|
|
|
|
case 2: // Reading length
|
|
|
|
if (inchar == ';') stage = 3;
|
|
|
|
else if (inchar >= '0' && inchar <= '9') len = (len << 4) | (inchar - '0');
|
|
|
|
else if (inchar >= 'A' && inchar <= 'F') len = (len << 4) | ((inchar - 'A') + 10);
|
|
|
|
else if (inchar >= 'a' && inchar <= 'f') len = (len << 4) | ((inchar - 'a') + 10);
|
|
|
|
else if (inchar == '\r') stage = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // Skipping chunk extension
|
|
|
|
case 4:
|
|
|
|
if (inchar == crlf[stage-3]) stage++;
|
|
|
|
else stage = 3;
|
|
|
|
if (stage == 5)
|
|
|
|
{
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// TranslateHTML
|
|
|
|
//
|
|
|
|
// Converts HTML text into something closer to plain-text and appends it
|
|
|
|
// to the edit control's contents.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
struct TranslateHTML
|
|
|
|
{
|
|
|
|
TranslateHTML (char *header, HWND editcontrol)
|
|
|
|
: edit(editcontrol), state(0), allowspace(false)
|
|
|
|
{
|
|
|
|
plaintext = strstr (header, "content-type: text/html") == NULL;
|
|
|
|
}
|
|
|
|
void Translate (char *buf);
|
|
|
|
|
|
|
|
HWND edit;
|
|
|
|
int state;
|
|
|
|
bool allowspace;
|
|
|
|
char token[64];
|
|
|
|
bool plaintext;
|
|
|
|
};
|
|
|
|
|
|
|
|
void TranslateHTML::Translate (char *buf)
|
|
|
|
{
|
|
|
|
char *in, *out;
|
|
|
|
int tokenp = 0;
|
|
|
|
bool endrange = false;
|
|
|
|
bool inhead = false, inscript = false;
|
|
|
|
|
|
|
|
if (plaintext)
|
|
|
|
{
|
|
|
|
SendMessage (edit, EM_REPLACESEL, 0, (LPARAM)buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (in = out = buf; *in != 0; in++)
|
|
|
|
{
|
|
|
|
char x = *in;
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case 0: // Not in a token
|
|
|
|
if (x == '<' || x == '&')
|
|
|
|
{
|
|
|
|
state = x == '<' ? 1 : 11;
|
|
|
|
}
|
|
|
|
else if (!inhead && !inscript)
|
|
|
|
{
|
|
|
|
if (x <= ' ')
|
|
|
|
{
|
|
|
|
if (allowspace)
|
|
|
|
{
|
|
|
|
allowspace = false;
|
|
|
|
*out++ = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*out++ = x;
|
|
|
|
allowspace = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // Just got a '<'
|
|
|
|
state = 2;
|
|
|
|
tokenp = 0;
|
|
|
|
if (x == '/')
|
|
|
|
{
|
|
|
|
endrange = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (x == '!')
|
|
|
|
{
|
|
|
|
state = 20;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
endrange = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 2: // Somewhere past '<'
|
|
|
|
if (x == '>')
|
|
|
|
{ // Token finished
|
|
|
|
gottoken:
|
|
|
|
token[tokenp] = 0;
|
|
|
|
if (!endrange)
|
|
|
|
{
|
|
|
|
if (stricmp (token, "head") == 0)
|
|
|
|
{
|
|
|
|
inhead = true;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "script") == 0)
|
|
|
|
{
|
|
|
|
inscript = true;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "p") == 0 || stricmp (token, "address") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
*out++ = '\n';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "br") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "li") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
*out++ = '*';
|
|
|
|
*out++ = ' ';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
else if ((token[0] == 'h' || token[0] == 'H') && token[1] >= '0' && token[1] <= '9' && token[2] == '\0')
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (stricmp (token, "head") == 0)
|
|
|
|
{
|
|
|
|
inhead = false;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "script") == 0)
|
|
|
|
{
|
|
|
|
inscript = false;
|
|
|
|
}
|
|
|
|
else if ((token[0] == 'h' || token[0] == 'H') && token[1] >= '0' && token[1] <= '9' && token[2] == '\0')
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
*out++ = '\n';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "ul") == 0 || stricmp (token, "ol") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '\n';
|
|
|
|
allowspace = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
else if (x == ' ')
|
|
|
|
{
|
|
|
|
state = 3;
|
|
|
|
}
|
|
|
|
else if (tokenp < 63)
|
|
|
|
{
|
|
|
|
token[tokenp++] = x;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // Past '<' TOKEN ' '
|
|
|
|
if (x == '>')
|
|
|
|
{ // Token finished
|
|
|
|
goto gottoken;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 11: // Just got a '&'
|
|
|
|
state = 12;
|
|
|
|
tokenp = 0;
|
|
|
|
|
|
|
|
case 12:
|
|
|
|
if (x == ';')
|
|
|
|
{ // Token finished
|
|
|
|
if (stricmp (token, "lt") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '<';
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "gt") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '>';
|
|
|
|
}
|
|
|
|
else if (stricmp (token, "amp") == 0)
|
|
|
|
{
|
|
|
|
*out++ = '&';
|
|
|
|
}
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
else if (tokenp < 63)
|
|
|
|
{
|
|
|
|
token[tokenp++] = x;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 20: // Just got "<!"
|
|
|
|
case 21: // Just got "<!-"
|
|
|
|
if (x == '-') state++;
|
|
|
|
else state = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 22: // Somewhere after "<!--"
|
|
|
|
case 23: // Just got '-'
|
|
|
|
if (x == '-') state++;
|
|
|
|
else state = 22;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 24: // Just got "--"
|
|
|
|
if (x == '>')
|
|
|
|
{
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
state = 22;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (out != buf)
|
|
|
|
{
|
|
|
|
*out++ = '\0';
|
|
|
|
SendMessage (edit, EM_REPLACESEL, 0, (LPARAM)buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ReadResponse
|
|
|
|
//
|
|
|
|
// Read the HTTP response. If file is not INVALID_HANDLE_VALUE, then the
|
|
|
|
// response is downloaded to the file. Otherwise, it is passed through
|
|
|
|
// TranslateHTML and into the upload dialog's edit control.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static bool ReadResponse (HWND hDlg, char *header, SOCKET sock, char *buf, int bufsize, HANDLE file)
|
|
|
|
{
|
|
|
|
HWND edit = GetDlgItem (hDlg, IDC_BOINGEDIT);
|
|
|
|
DWORD wrote;
|
|
|
|
int len, avail, totalRecv;
|
|
|
|
int recvBytes = 0;
|
|
|
|
POINT pt = { 0, 0 };
|
|
|
|
|
|
|
|
strlwr (header);
|
|
|
|
|
|
|
|
TranslateHTML translator (header, edit);
|
|
|
|
SendMessage (edit, WM_SETREDRAW, FALSE, 0);
|
|
|
|
|
|
|
|
if (strstr (header, "transfer-encoding: chunked") != NULL)
|
|
|
|
{ // Response body is chunked
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
len = GetChunkLen (sock);
|
|
|
|
if (len == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
if (len > bufsize-1) avail = bufsize-1;
|
|
|
|
else avail = len;
|
|
|
|
recvBytes = recv (sock, buf, avail, 0);
|
|
|
|
if (recvBytes == 0 || recvBytes == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
buf[recvBytes] = '\0';
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
WriteFile (file, buf, recvBytes, &wrote, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
translator.Translate (buf);
|
|
|
|
}
|
|
|
|
len -= recvBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Response body is uninterrupted
|
|
|
|
char *lenhead = strstr (header, "content-length: ");
|
|
|
|
if (lenhead != 0)
|
|
|
|
{
|
|
|
|
len = strtol (lenhead + 16, NULL, 10);
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
ShowWindow (GetDlgItem (hDlg, IDC_BOINGPROGRESS), SW_SHOW);
|
|
|
|
SendMessage (GetDlgItem (hDlg, IDC_BOINGPROGRESS), PBM_SETRANGE, 0, MAKELPARAM (0, (len + bufsize-2)/(bufsize-1)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
totalRecv = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (len == 0) avail = bufsize - 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
avail = len - totalRecv;
|
|
|
|
if (avail > bufsize - 1) avail = bufsize - 1;
|
|
|
|
}
|
|
|
|
recvBytes = recv (sock, buf, avail, 0);
|
|
|
|
if (recvBytes == 0 || recvBytes == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
totalRecv += recvBytes;
|
|
|
|
buf[recvBytes] = '\0';
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
SendMessage (GetDlgItem (hDlg, IDC_BOINGPROGRESS), PBM_SETPOS, totalRecv/(bufsize-1), 0);
|
|
|
|
WriteFile (file, buf, recvBytes, &wrote, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
translator.Translate (buf);
|
|
|
|
}
|
|
|
|
if (len != 0 && totalRecv >= len)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
SendMessage (edit, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
|
|
|
|
SendMessage (edit, WM_SETREDRAW, TRUE, 0);
|
|
|
|
InvalidateRect (edit, NULL, FALSE);
|
|
|
|
return recvBytes != SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CheckServerResponse
|
|
|
|
//
|
|
|
|
// Waits for a response from the server. If it doesn't get a 1xx or 2xx
|
|
|
|
// response, the response is displayed. The return value is either the
|
|
|
|
// response code or -1 if a socket error occurred.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static int CheckServerResponse (HWND hDlg, SOCKET sock, char *&header, char *buf, int bufsize)
|
|
|
|
{
|
|
|
|
int response;
|
|
|
|
|
|
|
|
header = GetHeader (sock);
|
|
|
|
if (header == NULL)
|
|
|
|
{
|
|
|
|
UploadFail (hDlg, "Error reading server response", WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
response = strtoul (strchr (header, ' '), NULL, 10);
|
|
|
|
if (response >= 300)
|
|
|
|
{
|
|
|
|
char *topline = strstr (header, "\r\n");
|
|
|
|
*topline = 0;
|
|
|
|
SetWindowText (GetDlgItem (hDlg, IDC_BOINGSTATUS), header);
|
|
|
|
*topline = '\r';
|
|
|
|
if (response != 304)
|
|
|
|
{
|
|
|
|
ReadResponse (hDlg, header, sock, buf, bufsize, INVALID_HANDLE_VALUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// CabinetCallback
|
|
|
|
//
|
|
|
|
// Used to extract dbghelp.dll out of the downloaded cabinet.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static UINT CALLBACK CabinetCallback (PVOID context, UINT notification, UINT_PTR param1, UINT_PTR param2)
|
|
|
|
{
|
|
|
|
if (notification == SPFILENOTIFY_FILEINCABINET)
|
|
|
|
{
|
|
|
|
FILE_IN_CABINET_INFO *info = (FILE_IN_CABINET_INFO *)param1;
|
|
|
|
if (strcmp (info->NameInCabinet, "dbghelp.dll") == 0)
|
|
|
|
{
|
|
|
|
strncpy (info->FullTargetName, (char *)context, sizeof(info->FullTargetName));
|
|
|
|
info->FullTargetName[sizeof(info->FullTargetName)-1] = '\0';
|
|
|
|
info->FullTargetName[strlen(info->FullTargetName)-1] = 'l';
|
|
|
|
return FILEOP_DOIT;
|
|
|
|
}
|
|
|
|
return FILEOP_SKIP;
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct UploadParmStruct
|
|
|
|
{
|
|
|
|
HWND hDlg;
|
|
|
|
HANDLE hThread;
|
|
|
|
HANDLE hFile;
|
|
|
|
const char *UserSummary;
|
|
|
|
};
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// UploadProc
|
|
|
|
//
|
|
|
|
// Drives the error report upload and optionally the dbghelp download,
|
|
|
|
// using standard HTTP requests.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static DWORD WINAPI UploadProc (LPVOID lpParam)
|
|
|
|
{
|
|
|
|
char dbghelpPath[MAX_PATH+12];
|
|
|
|
UploadParmStruct *parm = (UploadParmStruct *)lpParam;
|
|
|
|
char xferbuf[1024];
|
|
|
|
WSADATA wsad;
|
|
|
|
SOCKET sock = INVALID_SOCKET;
|
|
|
|
addrinfo aiHints = { 0 };
|
|
|
|
addrinfo *aiList = NULL;
|
|
|
|
char *header = NULL;
|
|
|
|
DWORD fileLen, fileLeft, contentLength;
|
|
|
|
int bytesSent;
|
|
|
|
int headerLen;
|
|
|
|
int err, i;
|
|
|
|
int retries;
|
|
|
|
DWORD returnval = TRUE;
|
|
|
|
HANDLE dbghelp = INVALID_HANDLE_VALUE;
|
|
|
|
HWND status = GetDlgItem (parm->hDlg, IDC_BOINGSTATUS);
|
|
|
|
|
|
|
|
dbghelpPath[0] = '\0';
|
|
|
|
SetWindowText (status, "Looking up " REMOTE_HOST "...");
|
|
|
|
|
|
|
|
// Startup Winsock. If this doesn't work, then we can't do anything.
|
|
|
|
err = WSAStartup (0x0101, &wsad);
|
|
|
|
if (err != 0)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not initialize Winsock", err);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
OSVERSIONINFO verinfo = { sizeof(verinfo) };
|
|
|
|
GetVersionEx (&verinfo);
|
|
|
|
if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
|
|
{
|
|
|
|
verinfo.dwBuildNumber &= 0xFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the host we want to talk with.
|
|
|
|
aiHints.ai_family = AF_INET;
|
|
|
|
aiHints.ai_socktype = SOCK_STREAM;
|
|
|
|
aiHints.ai_protocol = IPPROTO_TCP;
|
|
|
|
|
|
|
|
err = getaddrinfo (REMOTE_HOST, REMOTE_PORT, &aiHints, &aiList);
|
|
|
|
if (err != 0 || aiList == NULL)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not resolve " REMOTE_HOST, err);
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new socket...
|
|
|
|
sock = socket (aiList->ai_family, aiList->ai_socktype, aiList->ai_protocol);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not create socket", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int timeout = TIMEOUT;
|
|
|
|
setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
|
|
|
setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
|
|
|
|
|
|
|
// ...and connect it to the remote host.
|
|
|
|
SetWindowText (status, "Connecting to " REMOTE_HOST "...");
|
|
|
|
err = connect (sock, aiList->ai_addr, sizeof(*aiList->ai_addr));
|
|
|
|
if (err == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Failed to connect", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now tell the host we want to submit the report.
|
|
|
|
SetWindowText (status, "Sending HTTP request...");
|
|
|
|
fileLen = GetFileSize (parm->hFile, NULL);
|
|
|
|
contentLength = sizeof(MultipartInfoHeader)-1 + 8+9*7+2 + strlen(verinfo.szCSDVersion) +
|
|
|
|
(parm->UserSummary ? (sizeof(MultipartUserSummaryHeader)-1 + strlen(UserSummary)) : 0) +
|
|
|
|
sizeof(MultipartBinaryHeader)-1 +
|
|
|
|
sizeof(MultipartHeaderGZip)-1 + fileLen +
|
|
|
|
sizeof(MultipartFooter)-1;
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
headerLen = mysnprintf (xferbuf, countof(xferbuf), PostHeader, contentLength);
|
2006-02-24 04:48:15 +00:00
|
|
|
bytesSent = send (sock, xferbuf, headerLen, 0);
|
|
|
|
if (bytesSent != headerLen)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not send HTTP request", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for a 100 continue response from the host.
|
|
|
|
err = CheckServerResponse (parm->hDlg, sock, header, xferbuf, sizeof(xferbuf));
|
|
|
|
if (err < 0 || err >= 300)
|
|
|
|
{
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now that we have it, we can finally send the report.
|
|
|
|
SetWindowText (status, "Sending report...");
|
|
|
|
|
|
|
|
// First show the progress bar so the user knows how much of the report has been sent.
|
|
|
|
ShowWindow (GetDlgItem (parm->hDlg, IDC_BOINGPROGRESS), SW_SHOW);
|
|
|
|
SendMessage (GetDlgItem (parm->hDlg, IDC_BOINGPROGRESS), PBM_SETRANGE, 0, MAKELPARAM (0, (fileLen + sizeof(xferbuf)-1)/sizeof(xferbuf)));
|
|
|
|
|
|
|
|
// Send the bare-bones info (exception and windows version info)
|
|
|
|
bytesSent = send (sock, MultipartInfoHeader, sizeof(MultipartInfoHeader)-1, 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
headerLen = mysnprintf (xferbuf, countof(xferbuf), "Windows %08lX %p %X %08lX %08lX %08lX %08lX %08lX %s",
|
2006-02-24 04:48:15 +00:00
|
|
|
CrashPointers.ExceptionRecord->ExceptionCode,
|
|
|
|
CrashPointers.ExceptionRecord->ExceptionAddress,
|
|
|
|
!!CrashPointers.ExceptionRecord->ExceptionInformation[0],
|
|
|
|
CrashPointers.ExceptionRecord->ExceptionInformation[1],
|
|
|
|
|
|
|
|
verinfo.dwMajorVersion,
|
|
|
|
verinfo.dwMinorVersion,
|
|
|
|
verinfo.dwBuildNumber,
|
|
|
|
verinfo.dwPlatformId,
|
|
|
|
verinfo.szCSDVersion);
|
|
|
|
bytesSent = send (sock, xferbuf, headerLen, 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the user summary.
|
|
|
|
if (parm->UserSummary)
|
|
|
|
{
|
|
|
|
bytesSent = send (sock, MultipartUserSummaryHeader, sizeof(MultipartUserSummaryHeader)-1, 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
bytesSent = send (sock, parm->UserSummary, (int)strlen(parm->UserSummary), 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the report file.
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
headerLen = mysnprintf (xferbuf, countof(xferbuf), "%s%s", MultipartBinaryHeader, MultipartHeaderZip);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
bytesSent = send (sock, xferbuf, headerLen, 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the report itself.
|
|
|
|
SetFilePointer (parm->hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
fileLeft = fileLen;
|
|
|
|
i = 0;
|
|
|
|
while (fileLeft != 0)
|
|
|
|
{
|
|
|
|
DWORD grab = fileLeft > sizeof(xferbuf) ? sizeof(xferbuf) : fileLeft;
|
|
|
|
DWORD didread;
|
|
|
|
|
|
|
|
ReadFile (parm->hFile, xferbuf, grab, &didread, NULL);
|
|
|
|
bytesSent = send (sock, xferbuf, didread, 0);
|
|
|
|
if (bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not upload report", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
fileLeft -= grab;
|
|
|
|
SendMessage (GetDlgItem (parm->hDlg, IDC_BOINGPROGRESS), PBM_SETPOS, ++i, 0);
|
|
|
|
}
|
|
|
|
// Send the multipart footer.
|
|
|
|
bytesSent += send (sock, MultipartFooter, sizeof(MultipartFooter) - 1, 0);
|
|
|
|
|
|
|
|
// And now we're done uploading the report. Yay!
|
|
|
|
SetWindowText (status, "Report sent");
|
|
|
|
|
|
|
|
// But we still need a 200 response from the host. Hopefully it gives us one.
|
|
|
|
HeapFree (GetProcessHeap(), 0, header);
|
|
|
|
err = CheckServerResponse (parm->hDlg, sock, header, xferbuf, sizeof(xferbuf));
|
|
|
|
if (err < 0 || err >= 300)
|
|
|
|
{
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill the edit control with the response body, in case the host wants
|
|
|
|
// to say, "Thank you for clicking that send button."
|
|
|
|
ReadResponse (parm->hDlg, header, sock, xferbuf, sizeof(xferbuf), INVALID_HANDLE_VALUE);
|
|
|
|
|
|
|
|
// Close the connection, because we told the host this was a one-shot communication.
|
|
|
|
closesocket (sock); sock = INVALID_SOCKET;
|
|
|
|
|
|
|
|
// If dbghelp.dll was not available or too old when the report was created,
|
|
|
|
// ask the user if they want to download it. It's too late to be of any use
|
|
|
|
// to this report, but it can still be used for future reports.
|
|
|
|
if (NeedDbgHelp && MessageBox (parm->hDlg,
|
|
|
|
"Shall I download dbghelp.dll?\n\n"
|
|
|
|
"This is a Microsoft-supplied DLL that can gather detailed information when a program crashes.\n\n"
|
2006-06-24 08:26:21 +00:00
|
|
|
"Although it is not essential for "GAMENAME", it will make any future error\n"
|
2006-02-24 04:48:15 +00:00
|
|
|
"reports more useful, so it is strongly suggested that you answer \"yes.\"\n\n"
|
2006-06-24 08:26:21 +00:00
|
|
|
"If you answer \"yes,\" dbghelp.dll will be installed in the same directory as "GAMENAME".",
|
2006-02-24 04:48:15 +00:00
|
|
|
"Download dbghelp.dll?", MB_YESNO|MB_ICONQUESTION) == IDYES)
|
|
|
|
{
|
|
|
|
char *bs;
|
|
|
|
|
|
|
|
// Download it to the same directory as zdoom.exe.
|
|
|
|
GetModuleFileName (NULL, dbghelpPath, MAX_PATH);
|
|
|
|
dbghelpPath[MAX_PATH] = 0;
|
|
|
|
bs = strrchr (dbghelpPath, '\\');
|
|
|
|
if (bs != NULL)
|
|
|
|
{
|
|
|
|
strcpy (bs + 1, "dbghelp.dl_");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (dbghelpPath, "dbghelp.dl_");
|
|
|
|
}
|
|
|
|
dbghelp = CreateFile (dbghelpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
|
|
|
if (dbghelp != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
SetWindowText (status, "Receiving dbghelp...");
|
|
|
|
retries = 0;
|
|
|
|
|
|
|
|
// Reopen the socket. We don't need to repeat the lookup, because
|
|
|
|
// we already know where the host is.
|
|
|
|
SetWindowText (status, "Reconnecting to " REMOTE_HOST "...");
|
|
|
|
sock = socket (aiList->ai_family, aiList->ai_socktype, aiList->ai_protocol);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not create socket", WSAGetLastError());
|
|
|
|
throw 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Socket is open. Try reconnecting now.
|
|
|
|
err = connect (sock, aiList->ai_addr, sizeof(*aiList->ai_addr));
|
|
|
|
if (err == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Failed to reconnect", WSAGetLastError());
|
|
|
|
throw 2;
|
|
|
|
}
|
|
|
|
SetWindowText (status, "Receiving dbghelp...");
|
|
|
|
|
|
|
|
// And send the request.
|
|
|
|
bytesSent = send (sock, DbgHelpRequest, sizeof(DbgHelpRequest)-1, 0);
|
|
|
|
if (bytesSent == 0 || bytesSent == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Failed trying to request dbghelp", WSAGetLastError());
|
|
|
|
throw 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore any information replies from the server. There shouldn't be any,
|
|
|
|
// but this loop is here just in case.
|
|
|
|
err = 100;
|
|
|
|
while (err / 100 == 1)
|
|
|
|
{
|
|
|
|
HeapFree (GetProcessHeap(), 0, header);
|
|
|
|
err = CheckServerResponse (parm->hDlg, sock, header, xferbuf, sizeof(xferbuf));
|
|
|
|
}
|
|
|
|
// Now, if we haven't received a 200 OK response, give up because we
|
|
|
|
// shouldn't receive anything but that.
|
|
|
|
if (err != 200)
|
|
|
|
{
|
|
|
|
throw 2;
|
|
|
|
}
|
|
|
|
// Write the response body to the dbghelp.dl_ file.
|
|
|
|
if (!ReadResponse (parm->hDlg, header, sock, xferbuf, sizeof(xferbuf), dbghelp))
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Could not receive dbghelp", WSAGetLastError());
|
|
|
|
throw 2;
|
|
|
|
}
|
|
|
|
CloseHandle (dbghelp); dbghelp = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
// Now use the Setup API to extract dbghelp.dll from the file we just downloaded.
|
|
|
|
if (!SetupIterateCabinet (dbghelpPath, 0, CabinetCallback, dbghelpPath))
|
|
|
|
{
|
|
|
|
UploadFail (parm->hDlg, "Extraction of dbghelp failed", GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now we're done with that. There's nothing more to do here now.
|
|
|
|
SetWindowText (status, "Dbghelp installed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
returnval = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ShowWindow (GetDlgItem (parm->hDlg, IDC_BOINGPROGRESS), SW_HIDE);
|
|
|
|
KillTimer (parm->hDlg, 1);
|
|
|
|
EnableWindow (GetDlgItem (parm->hDlg, IDOK), TRUE);
|
|
|
|
EnableWindow (GetDlgItem (parm->hDlg, IDC_BOINGEDIT), TRUE);
|
|
|
|
|
|
|
|
if (dbghelp != INVALID_HANDLE_VALUE) CloseHandle (dbghelp);
|
|
|
|
if (dbghelpPath[0] != '\0') DeleteFile (dbghelpPath);
|
|
|
|
if (header != NULL) HeapFree (GetProcessHeap(), 0, header);
|
|
|
|
if (sock != INVALID_SOCKET) closesocket (sock);
|
|
|
|
if (aiList != NULL) freeaddrinfo (aiList);
|
|
|
|
WSACleanup ();
|
|
|
|
return returnval;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// BoingDlgProc
|
|
|
|
//
|
|
|
|
// The dialog procedure for the upload status dialog. Aside from spawning
|
|
|
|
// off a new thread executing UploadProc, it doesn't do a whole lot.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static BOOL CALLBACK BoingDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
UploadParmStruct *parms = (UploadParmStruct *)lParam;
|
|
|
|
HWND ctrl;
|
|
|
|
WLONG_PTR iconNum;
|
|
|
|
HANDLE icon;
|
|
|
|
DWORD threadID;
|
|
|
|
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetTimer (hDlg, 1, 100, NULL);
|
|
|
|
ctrl = GetDlgItem (hDlg, IDC_BOING);
|
|
|
|
SetWindowLongPtr (ctrl, GWLP_USERDATA, IDI_BOING1);
|
|
|
|
parms->hDlg = hDlg;
|
|
|
|
parms->hThread = CreateThread (NULL, 0, UploadProc, parms, 0, &threadID);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case WM_TIMER:
|
|
|
|
if (wParam == 1)
|
|
|
|
{
|
|
|
|
ctrl = GetDlgItem (hDlg, IDC_BOING);
|
|
|
|
iconNum = GetWindowLongPtr (ctrl, GWLP_USERDATA) + 1;
|
|
|
|
if (iconNum > IDI_BOING8) iconNum = IDI_BOING1;
|
|
|
|
SetWindowLongPtr (ctrl, GWLP_USERDATA, iconNum);
|
|
|
|
icon = LoadImage (g_hInst, MAKEINTRESOURCE(iconNum), IMAGE_ICON, 32, 32, LR_SHARED|LR_DEFAULTCOLOR);
|
|
|
|
SendMessage (ctrl, STM_SETICON, (WPARAM)icon, 0);
|
|
|
|
InvalidateRect (ctrl, NULL, FALSE);
|
|
|
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
|
|
{
|
|
|
|
KillTimer (hDlg, 1);
|
|
|
|
EndDialog (hDlg, LOWORD(wParam));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// UploadReport
|
|
|
|
//
|
|
|
|
// Starts off the upload by showing the upload dialog.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static BOOL UploadReport (HANDLE file)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
UploadParmStruct uploadParm = { 0, 0, file, UserSummary };
|
2006-02-24 04:48:15 +00:00
|
|
|
BOOL res = (BOOL)DialogBoxParam (g_hInst, MAKEINTRESOURCE(IDD_BOING), NULL, (DLGPROC)BoingDlgProc, (LPARAM)&uploadParm);
|
|
|
|
if (UserSummary != NULL)
|
|
|
|
{
|
|
|
|
HeapFree (GetProcessHeap(), 0, UserSummary);
|
|
|
|
UserSummary = NULL;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // #if 0
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// SaveReport
|
|
|
|
//
|
|
|
|
// Makes a permanent copy of the report tarball.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-06-24 03:47:17 +00:00
|
|
|
static void SaveReport (HANDLE file)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
OPENFILENAME ofn = {
|
|
|
|
#ifdef OPENFILENAME_SIZE_VERSION_400
|
|
|
|
OPENFILENAME_SIZE_VERSION_400
|
|
|
|
#else
|
|
|
|
sizeof(ofn)
|
|
|
|
#endif
|
|
|
|
, };
|
|
|
|
char filename[256];
|
|
|
|
|
2006-06-24 03:48:38 +00:00
|
|
|
ofn.lpstrFilter = "Zip file (*.zip)\0*.zip\0";
|
|
|
|
strcpy (filename, "CrashReport.zip");
|
2006-02-24 04:48:15 +00:00
|
|
|
ofn.lpstrFile = filename;
|
|
|
|
ofn.nMaxFile = sizeof(filename);
|
|
|
|
|
|
|
|
while (GetSaveFileName (&ofn))
|
|
|
|
{
|
|
|
|
HANDLE ofile = CreateFile (ofn.lpstrFile, GENERIC_WRITE, 0, NULL,
|
|
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,
|
|
|
|
NULL);
|
|
|
|
if (ofile == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
if (MessageBox (NULL, "Could not open the crash report file",
|
|
|
|
"Save As failed", MB_RETRYCANCEL) == IDRETRY)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DWORD fileLen = GetFileSize (file, NULL), fileLeft;
|
|
|
|
char xferbuf[1024];
|
|
|
|
|
|
|
|
SetFilePointer (file, 0, NULL, FILE_BEGIN);
|
|
|
|
fileLeft = fileLen;
|
|
|
|
while (fileLeft != 0)
|
|
|
|
{
|
|
|
|
DWORD grab = fileLeft > sizeof(xferbuf) ? sizeof(xferbuf) : fileLeft;
|
|
|
|
DWORD didread;
|
|
|
|
|
|
|
|
ReadFile (file, xferbuf, grab, &didread, NULL);
|
|
|
|
WriteFile (ofile, xferbuf, didread, &grab, NULL);
|
|
|
|
fileLeft -= didread;
|
|
|
|
}
|
|
|
|
CloseHandle (ofile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// DisplayCrashLog
|
|
|
|
//
|
|
|
|
// Displays the crash information and possibly submits it. CreateCrashLog()
|
|
|
|
// must have been called previously.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void DisplayCrashLog ()
|
|
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
|
2007-01-09 04:40:58 +00:00
|
|
|
if (NumFiles == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
char ohPoo[] =
|
2006-06-24 08:26:21 +00:00
|
|
|
GAMENAME" crashed but was unable to produce\n"
|
2006-02-24 04:48:15 +00:00
|
|
|
"detailed information about the crash.\n"
|
|
|
|
"\nThis is all that is available:\n\nCode=XXXXXXXX\nAddr=XXXXXXXX";
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf (ohPoo + countof(ohPoo) - 23, 23, "%08lX\nAddr=%p", CrashCode, CrashAddress);
|
2006-06-24 08:26:21 +00:00
|
|
|
MessageBox (NULL, ohPoo, GAMENAME" Very Fatal Error", MB_OK|MB_ICONSTOP);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (WinHlp32 != NULL)
|
|
|
|
{
|
|
|
|
FreeLibrary (WinHlp32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
HMODULE uxtheme = LoadLibrary ("uxtheme.dll");
|
|
|
|
if (uxtheme != NULL)
|
|
|
|
{
|
|
|
|
pEnableThemeDialogTexture = (HRESULT (__stdcall *)(HWND,DWORD))GetProcAddress (uxtheme, "EnableThemeDialogTexture");
|
|
|
|
}
|
|
|
|
INT_PTR result = DialogBox (g_hInst, MAKEINTRESOURCE(IDD_CRASHDIALOG), NULL, (DLGPROC)CrashDlgProc);
|
|
|
|
if (result == IDYES)
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
#if 0 // Server-side support is not done yet because I am too lazy.
|
|
|
|
file = MakeZip ();
|
|
|
|
UploadReport (file);
|
2006-02-24 04:48:15 +00:00
|
|
|
CloseHandle (file);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (result == IDC_SAVEREPORT)
|
|
|
|
{
|
2006-06-24 03:47:17 +00:00
|
|
|
file = MakeZip ();
|
|
|
|
SaveReport (file);
|
2006-02-24 04:48:15 +00:00
|
|
|
CloseHandle (file);
|
|
|
|
}
|
|
|
|
if (uxtheme != NULL)
|
|
|
|
{
|
|
|
|
FreeLibrary (uxtheme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CloseTarFiles ();
|
|
|
|
}
|