archutils\Win32\ cleanup and comment
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
|
||||
AppInstance::AppInstance()
|
||||
{
|
||||
/* Little trick to get an HINSTANCE of ourself without having access to the hwnd ... */
|
||||
// Little trick to get an HINSTANCE of ourself without having access to the hwnd.
|
||||
TCHAR szFullAppPath[MAX_PATH];
|
||||
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
|
||||
h = LoadLibrary(szFullAppPath);
|
||||
/* h will be NULL if this fails. Most operations that take an HINSTANCE
|
||||
/* h will be NULL if this fails. Most operations that take an HINSTANCE
|
||||
* will still work without one (but may be missing graphics); that's OK. */
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* AppInstance - get an HINSTANCE for starting dialog boxes. */
|
||||
|
||||
#ifndef APP_INSTANCE_H
|
||||
#define APP_INSTANCE_H
|
||||
|
||||
@@ -7,6 +5,7 @@
|
||||
# include "windows.h"
|
||||
#endif
|
||||
|
||||
/** @brief get an HINSTANCE for starting dialog boxes. */
|
||||
class AppInstance
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "CommandLine.h"
|
||||
#include <windows.h>
|
||||
|
||||
/* Ugh. Windows doesn't give us the argv[] parser; all it gives is CommandLineToArgvW,
|
||||
* which is NT-only, so we have to do this ourself. Don't be fancy; only handle double
|
||||
* quotes. */
|
||||
/* Ugh. Windows doesn't give us the argv[] parser; all it gives is
|
||||
* CommandLineToArgvW, which is NT-only, so we have to do this ourself. Don't
|
||||
* be fancy; only handle double quotes. */
|
||||
int GetWin32CmdLine( char** &argv )
|
||||
{
|
||||
char *pCmdLine = GetCommandLine();
|
||||
@@ -18,19 +18,19 @@ int GetWin32CmdLine( char** &argv )
|
||||
argv[argc] = pCmdLine+i;
|
||||
++argc;
|
||||
|
||||
/* Skip to the end of this argument. */
|
||||
// Skip to the end of this argument.
|
||||
while( pCmdLine[i] && pCmdLine[i] != ' ' )
|
||||
{
|
||||
if( pCmdLine[i] == '"' )
|
||||
{
|
||||
/* Erase the quote. */
|
||||
// Erase the quote.
|
||||
memmove( pCmdLine+i, pCmdLine+i+1, strlen(pCmdLine+i+1)+1 );
|
||||
|
||||
/* Skip to the close quote. */
|
||||
// Skip to the close quote.
|
||||
while( pCmdLine[i] && pCmdLine[i] != '"' )
|
||||
++i;
|
||||
|
||||
/* Erase the close quote. */
|
||||
// Erase the close quote.
|
||||
if( pCmdLine[i] == '"' )
|
||||
memmove( pCmdLine+i, pCmdLine+i+1, strlen(pCmdLine+i+1)+1 );
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* Helper to simulate standard argv[] semantics with WinMain. */
|
||||
|
||||
#ifndef CommandLine_H
|
||||
#define CommandLine_H
|
||||
|
||||
/** @brief Helper to simulate standard argv[] semantics with WinMain. */
|
||||
int GetWin32CmdLine( char** &argv );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include "arch/Threads/Threads_Win32.h"
|
||||
#include "crash.h"
|
||||
#include "CrashHandlerInternal.h"
|
||||
#include "RageLog.h" /* for RageLog::GetAdditionalLog and Flush */
|
||||
#include "RageThreads.h" /* for GetCheckpointLogs */
|
||||
#include "PrefsManager.h" /* for g_bAutoRestart */
|
||||
#include "RageLog.h" // for RageLog::GetAdditionalLog and Flush
|
||||
#include "RageThreads.h" // for GetCheckpointLogs
|
||||
#include "PrefsManager.h" // for g_bAutoRestart
|
||||
#include "RestartProgram.h"
|
||||
|
||||
// WARNING: This is called from crash-time conditions! No malloc() or new!!!
|
||||
@@ -18,7 +18,6 @@
|
||||
#define malloc not_allowed_here
|
||||
#define new not_allowed_here
|
||||
|
||||
|
||||
static void SpliceProgramPath(char *buf, int bufsiz, const char *fn) {
|
||||
char tbuf[MAX_PATH];
|
||||
char *pszFile;
|
||||
@@ -91,7 +90,7 @@ void WriteToChild( HANDLE hPipe, const void *pData, size_t iSize )
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute the child process. Return a handle to the process, a writable handle
|
||||
/* Execute the child process. Return a handle to the process, a writable handle
|
||||
* to its stdin, and a readable handle to its stdout. */
|
||||
bool StartChild( HANDLE &hProcess, HANDLE &hToStdin, HANDLE &hFromStdout )
|
||||
{
|
||||
@@ -186,7 +185,8 @@ void RunChild()
|
||||
HANDLE hProcess, hToStdin, hFromStdout;
|
||||
StartChild( hProcess, hToStdin, hFromStdout );
|
||||
|
||||
/* 0. Send a handle of this process to the crash handling process, which it can use to handle symbol lookups. */
|
||||
// 0. Send a handle of this process to the crash handling process, which it
|
||||
// can use to handle symbol lookups.
|
||||
{
|
||||
HANDLE hTargetHandle;
|
||||
DuplicateHandle(
|
||||
@@ -202,54 +202,54 @@ void RunChild()
|
||||
WriteToChild( hToStdin, &hTargetHandle, sizeof(hTargetHandle) );
|
||||
}
|
||||
|
||||
/* 1. Write the CrashData. */
|
||||
// 1. Write the CrashData.
|
||||
WriteToChild( hToStdin, &g_CrashInfo, sizeof(g_CrashInfo) );
|
||||
|
||||
/* 2. Write info. */
|
||||
const char *p = RageLog::GetInfo();
|
||||
int iSize = strlen( p );
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
// 2. Write info.
|
||||
const char *p = RageLog::GetInfo();
|
||||
int iSize = strlen( p );
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
|
||||
/* 3. Write AdditionalLog. */
|
||||
p = RageLog::GetAdditionalLog();
|
||||
iSize = strlen( p );
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
// 3. Write AdditionalLog.
|
||||
p = RageLog::GetAdditionalLog();
|
||||
iSize = strlen( p );
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
|
||||
/* 4. Write RecentLogs. */
|
||||
int cnt = 0;
|
||||
const char *ps[1024];
|
||||
while( cnt < 1024 && (ps[cnt] = RageLog::GetRecentLog( cnt )) != NULL )
|
||||
++cnt;
|
||||
// 4. Write RecentLogs.
|
||||
int cnt = 0;
|
||||
const char *ps[1024];
|
||||
while( cnt < 1024 && (ps[cnt] = RageLog::GetRecentLog( cnt )) != NULL )
|
||||
++cnt;
|
||||
|
||||
WriteToChild(hToStdin, &cnt, sizeof(cnt));
|
||||
for( int i = 0; i < cnt; ++i )
|
||||
{
|
||||
iSize = strlen(ps[i])+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, ps[i], iSize );
|
||||
}
|
||||
WriteToChild(hToStdin, &cnt, sizeof(cnt));
|
||||
for( int i = 0; i < cnt; ++i )
|
||||
{
|
||||
iSize = strlen(ps[i])+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, ps[i], iSize );
|
||||
}
|
||||
|
||||
/* 5. Write CHECKPOINTs. */
|
||||
static char buf[1024*32];
|
||||
Checkpoints::GetLogs( buf, sizeof(buf), "$$" );
|
||||
iSize = strlen( buf )+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, buf, iSize );
|
||||
// 5. Write CHECKPOINTs.
|
||||
static char buf[1024*32];
|
||||
Checkpoints::GetLogs( buf, sizeof(buf), "$$" );
|
||||
iSize = strlen( buf )+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, buf, iSize );
|
||||
|
||||
/* 6. Write the crashed thread's name. */
|
||||
p = RageThread::GetCurrentThreadName();
|
||||
iSize = strlen( p )+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
// 6. Write the crashed thread's name.
|
||||
p = RageThread::GetCurrentThreadName();
|
||||
iSize = strlen( p )+1;
|
||||
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
|
||||
WriteToChild( hToStdin, p, iSize );
|
||||
|
||||
/* The parent process needs to access this process briefly. When it's done, it'll
|
||||
* close the handle. Wait until we see that before exiting. */
|
||||
/* The parent process needs to access this process briefly. When it's done,
|
||||
* it'll close the handle. Wait until we see that before exiting. */
|
||||
while(1)
|
||||
{
|
||||
/* Ugly: the new process can't execute GetModuleFileName on this process,
|
||||
* since GetModuleFileNameEx might not be available. Run the requests here. */
|
||||
* since GetModuleFileNameEx might not be available. Run the requests here. */
|
||||
HMODULE hMod;
|
||||
DWORD iActual;
|
||||
if( !ReadFile( hFromStdout, &hMod, sizeof(hMod), &iActual, NULL) )
|
||||
@@ -266,23 +266,21 @@ void RunChild()
|
||||
|
||||
static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
{
|
||||
/* Flush the log it isn't cut off at the end. */
|
||||
// Flush the log so it isn't cut off at the end.
|
||||
/* 1. We can't do regular file access in the crash handler.
|
||||
* 2. We can't access LOG itself at all, since it may not be set up or the pointer might
|
||||
* be munged. We must only ever use the RageLog:: methods that access static data, that
|
||||
* we're being very careful to null-terminate as needed.
|
||||
*
|
||||
* Logs are rarely important, anyway. Only info.txt and crashinfo.txt are needed 99%
|
||||
* of the time. */
|
||||
* 2. We can't access LOG itself at all, since it may not be set up or the
|
||||
* pointer might be munged. We must only ever use the RageLog:: methods that
|
||||
* access static data, that we're being very careful to null-terminate as needed.
|
||||
* Logs are rarely important, anyway. Only info.txt and crashinfo.txt are
|
||||
* needed 99% of the time. */
|
||||
// LOG->Flush();
|
||||
|
||||
/* We aren't supposed to receive these exceptions. For example, if you do
|
||||
* a floating point divide by zero, you should receive a result of #INF. Only
|
||||
* if the floating point exception for _EM_ZERODIVIDE is unmasked does this
|
||||
* exception occur, and we never unmask it.
|
||||
*
|
||||
/* We aren't supposed to receive these exceptions. For example, if you do
|
||||
* a floating point divide by zero, you should receive a result of #INF.
|
||||
* Only if the floating point exception for _EM_ZERODIVIDE is unmasked
|
||||
* does this exception occur, and we never unmask it.
|
||||
* However, once in a while some driver or library turns evil and unmasks an
|
||||
* exception flag on us. If this happens, re-mask it and continue execution. */
|
||||
* exception flag on us. If this happens, re-mask it and continue execution. */
|
||||
switch( pExc->ExceptionRecord->ExceptionCode )
|
||||
{
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
@@ -298,14 +296,14 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
static int InHere = 0;
|
||||
if( InHere > 0 )
|
||||
{
|
||||
/* If we get here, then we've been called recursively, which means we crashed.
|
||||
* If InHere is greater than 1, then we crashed after writing the crash dump;
|
||||
* say so. */
|
||||
/* If we get here, then we've been called recursively, which means we
|
||||
* crashed. If InHere is greater than 1, then we crashed after writing
|
||||
* the crash dump; say so. */
|
||||
SetUnhandledExceptionFilter(NULL);
|
||||
MessageBox( NULL,
|
||||
InHere == 1?
|
||||
"The error reporting interface has crashed.\n":
|
||||
"The error reporting interface has crashed. However, crashinfo.txt was"
|
||||
"The error reporting interface has crashed. However, crashinfo.txt was"
|
||||
"written successfully to the program directory.\n",
|
||||
"Fatal Error", MB_OK );
|
||||
#ifdef DEBUG
|
||||
@@ -330,17 +328,17 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
if( g_bAutoRestart )
|
||||
Win32RestartProgram();
|
||||
|
||||
/* Now things get more risky. If we're fullscreen, the window will obscure the
|
||||
* crash dialog. Try to hide the window. Things might blow up here; do this
|
||||
* after DoSave, so we always write a crash dump. */
|
||||
/* Now things get more risky. If we're fullscreen, the window will obscure
|
||||
* the crash dialog. Try to hide the window. Things might blow up here; do
|
||||
* this after DoSave, so we always write a crash dump. */
|
||||
if( GetWindowThreadProcessId( g_hForegroundWnd, NULL ) == GetCurrentThreadId() )
|
||||
{
|
||||
/* The thread that crashed was the thread that created the main window. Hide
|
||||
* the window. This will also restore the video mode, if necessary. */
|
||||
/* The thread that crashed was the thread that created the main window.
|
||||
* Hide the window. This will also restore the video mode, if necessary. */
|
||||
ShowWindow( g_hForegroundWnd, SW_HIDE );
|
||||
} else {
|
||||
/* A different thread crashed. Simply kill all other windows. We can't safely
|
||||
* call ShowWindow; the main thread might be deadlocked. */
|
||||
/* A different thread crashed. Simply kill all other windows. We can't
|
||||
* safely call ShowWindow; the main thread might be deadlocked. */
|
||||
RageThread::HaltAllThreads( true );
|
||||
ChangeDisplaySettings( NULL, 0 );
|
||||
}
|
||||
@@ -349,8 +347,8 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
|
||||
SetUnhandledExceptionFilter( NULL );
|
||||
|
||||
/* Forcibly terminate; if we keep going, we'll try to shut down threads and do other
|
||||
* things that may deadlock, which is confusing for users. */
|
||||
/* Forcibly terminate; if we keep going, we'll try to shut down threads and
|
||||
* do other things that may deadlock, which is confusing for users. */
|
||||
TerminateProcess( GetCurrentProcess(), 0 );
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
@@ -358,8 +356,9 @@ static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
|
||||
long __stdcall CrashHandler::ExceptionHandler( EXCEPTION_POINTERS *pExc )
|
||||
{
|
||||
/* If the stack overflowed, we have a very limited amount of stack space. Allocate
|
||||
* a new stack, and run the exception handler in it, to increase the chances of success. */
|
||||
/* If the stack overflowed, we have a very limited amount of stack space.
|
||||
* Allocate a new stack, and run the exception handler in it, to increase
|
||||
* the chances of success. */
|
||||
int iSize = 1024*32;
|
||||
char *pStack = (char *) VirtualAlloc( NULL, iSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
|
||||
pStack += iSize;
|
||||
@@ -419,15 +418,14 @@ static bool IsValidCall(char *buf, int len)
|
||||
static bool IsExecutableProtection(DWORD dwProtect) {
|
||||
MEMORY_BASIC_INFORMATION meminfo;
|
||||
|
||||
// Windows NT/2000 allows Execute permissions, but Win9x seems to
|
||||
// rip it off. So we query the permissions on our own code block,
|
||||
// and use it to determine if READONLY/READWRITE should be
|
||||
// considered 'executable.'
|
||||
// Windows NT/2000 allows Execute permissions, but Win9x seems to rip it
|
||||
// off. So we query the permissions on our own code block, and use it to
|
||||
// determine if READONLY/READWRITE should be considered 'executable.'
|
||||
|
||||
VirtualQuery(IsExecutableProtection, &meminfo, sizeof meminfo);
|
||||
|
||||
switch((unsigned char)dwProtect) {
|
||||
case PAGE_READONLY: // *sigh* Win9x...
|
||||
case PAGE_READONLY: // *sigh* Win9x...
|
||||
case PAGE_READWRITE: // *sigh*
|
||||
return meminfo.Protect==PAGE_READONLY || meminfo.Protect==PAGE_READWRITE;
|
||||
|
||||
@@ -459,16 +457,17 @@ void CrashHandler::do_backtrace( const void **buf, size_t size,
|
||||
const void **pLast = buf + size - 1;
|
||||
bool bFirst = true;
|
||||
|
||||
/* The EIP of the position that crashed is normally on the stack, since the exception
|
||||
* handler was called on the same stack. However, once in a while, due to stack corruption,
|
||||
* we might not be able to get any frames from the stack. Pull it out of pContext->Eip,
|
||||
* which is always valid, and then discard the first stack frame if it's the same. */
|
||||
/* The EIP of the position that crashed is normally on the stack, since the
|
||||
* exception handler was called on the same stack. However, once in a while,
|
||||
* due to stack corruption, we might not be able to get any frames from the
|
||||
* stack. Pull it out of pContext->Eip, which is always valid, and then
|
||||
* discard the first stack frame if it's the same. */
|
||||
if( buf+1 != pLast && pContext->Eip != NULL )
|
||||
{
|
||||
*buf = (void *) pContext->Eip;
|
||||
++buf;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve stack pointers.
|
||||
const char *pStackBase;
|
||||
{
|
||||
@@ -527,7 +526,7 @@ void CrashHandler::do_backtrace( const void **buf, size_t size,
|
||||
*buf = NULL;
|
||||
}
|
||||
|
||||
/* Trigger the crash handler. This works even in the debugger. */
|
||||
// Trigger the crash handler. This works even in the debugger.
|
||||
static void NORETURN debug_crash()
|
||||
{
|
||||
__try {
|
||||
@@ -539,26 +538,26 @@ static void NORETURN debug_crash()
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a stack trace of the current thread and the specified thread. If
|
||||
* iID == GetInvalidThreadId(), then output a stack trace for every thread. */
|
||||
/* Get a stack trace of the current thread and the specified thread.
|
||||
* If iID == GetInvalidThreadId(), then output a stack trace for every thread. */
|
||||
void CrashHandler::ForceDeadlock( RString reason, uint64_t iID )
|
||||
{
|
||||
strncpy( g_CrashInfo.m_CrashReason, reason, sizeof(g_CrashInfo.m_CrashReason) );
|
||||
g_CrashInfo.m_CrashReason[ sizeof(g_CrashInfo.m_CrashReason)-1 ] = 0;
|
||||
|
||||
/* Suspend the other thread we're going to backtrace. (We need to at least suspend
|
||||
* hThread, for GetThreadContext to work.) */
|
||||
/* Suspend the other thread we're going to backtrace. (We need to at least
|
||||
* suspend hThread, for GetThreadContext to work.) */
|
||||
RageThread::HaltAllThreads( false );
|
||||
|
||||
if( iID == GetInvalidThreadId() )
|
||||
{
|
||||
/* Backtrace all threads. */
|
||||
// Backtrace all threads.
|
||||
int iCnt = 0;
|
||||
for( int i = 0; RageThread::EnumThreadIDs(i, iID); ++i )
|
||||
{
|
||||
if( iID == GetInvalidThreadId() )
|
||||
continue;
|
||||
|
||||
|
||||
if( iID == GetCurrentThreadId() )
|
||||
continue;
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* Win32 crash handling. */
|
||||
|
||||
#ifndef CRASH_H
|
||||
#define CRASH_H
|
||||
#include <windows.h>
|
||||
/** @brief Win32 crash handling. */
|
||||
namespace CrashHandler
|
||||
{
|
||||
extern long __stdcall ExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo);
|
||||
@@ -12,9 +11,9 @@ namespace CrashHandler
|
||||
void ForceCrash( const char *reason );
|
||||
void ForceDeadlock( RString reason, uint64_t iID );
|
||||
|
||||
/* Inform the crash handler of a foreground window that may be fullscreen. If
|
||||
* set, the crash handler will attempt to hide the window or reset the video
|
||||
* mode. */
|
||||
/* Inform the crash handler of a foreground window that may be fullscreen.
|
||||
* If set, the crash handler will attempt to hide the window or reset the
|
||||
* video mode. */
|
||||
void SetForegroundWindow( HWND hWnd );
|
||||
|
||||
void CrashHandlerHandleArgs( int argc, char* argv[] );
|
||||
|
||||
@@ -14,42 +14,39 @@
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This has an arch-like abstraction layout, since it's intended to become one.
|
||||
* It'll be moved out of here as things get polished further. The Winsock and
|
||||
/* This has an arch-like abstraction layout, since it's intended to become one.
|
||||
* It'll be moved out of here as things get polished further. The Winsock and
|
||||
* BSD implementations will be kept separate, since while they look similar,
|
||||
* they're different in the details, especially when you want to cleanly support
|
||||
* cancellation.
|
||||
*
|
||||
* Design notes:
|
||||
*
|
||||
* - Allow cancellation at any time. The only thing more annoying than a laggy
|
||||
* network, is an application that won't immediately respond to cancelling.
|
||||
* (This is even more important here, since we're using this after a crash.)
|
||||
* - Assume some operations and/or some architectures are going to have problems
|
||||
* doing everything nonblockingly, and do everything in a thread. This also allows
|
||||
* more complex network interactions, since it doesn't need to maintain an equally
|
||||
* complex state machine.
|
||||
* - When an operation is cancelled or an error occurs, all operations until the
|
||||
* next call to Close() become no-ops. This allows lenient error checking; it's
|
||||
* guaranteed that further calls to Read or Write will not reset the error state.
|
||||
* - The only function that may be called from another thread without serialization is
|
||||
* Cancel().
|
||||
* - Allow cancellation at any time. The only thing more annoying than a laggy
|
||||
* network, is an application that won't immediately respond to cancelling.
|
||||
* (This is even more important here, since we're using this after a crash.)
|
||||
* - Assume some operations and/or some architectures are going to have problems
|
||||
* doing everything nonblockingly, and do everything in a thread. This also allows
|
||||
* more complex network interactions, since it doesn't need to maintain an equally
|
||||
* complex state machine.
|
||||
* - When an operation is cancelled or an error occurs, all operations until the
|
||||
* next call to Close() become no-ops. This allows lenient error checking; it's
|
||||
* guaranteed that further calls to Read or Write will not reset the error state.
|
||||
* - The only function that may be called from another thread without serialization is
|
||||
* Cancel().
|
||||
*
|
||||
* All calls are blocking, except for:
|
||||
*
|
||||
* - Cancel(), which is always nonblocking. The operation in progress, if any,
|
||||
* will be aborted immediately. (The only exception here is incomplete
|
||||
* implementations, which may block);
|
||||
* - Close(), if Shutdown() was called first, since the necessary blocking occurs
|
||||
* during Shutdown;
|
||||
* - Close(), if an error or cancellation occurred.
|
||||
* - Cancel(), which is always nonblocking. The operation in progress, if any,
|
||||
* will be aborted immediately. (The only exception here is incomplete
|
||||
* implementations, which may block);
|
||||
* - Close(), if Shutdown() was called first, since the necessary blocking occurs
|
||||
* during Shutdown;
|
||||
* - Close(), if an error or cancellation occurred.
|
||||
*
|
||||
* Accepting incoming TCP connections is beyond the immediate scope of this interface
|
||||
* (that would involve a second listener class, which would be a factory for NetworkStream).
|
||||
* UDP is probably within the scope of this class, but there are some outstanding design
|
||||
* issues and it's beyond the work I'm doing right now.
|
||||
*/
|
||||
* issues and it's beyond the work I'm doing right now. */
|
||||
|
||||
class NetworkStream
|
||||
{
|
||||
@@ -62,58 +59,44 @@ public:
|
||||
NetworkStream() { }
|
||||
virtual ~NetworkStream() { }
|
||||
|
||||
/*
|
||||
* Open a connection. Must be in STATE_IDLE.
|
||||
*/
|
||||
// Open a connection. Must be in STATE_IDLE.
|
||||
virtual void Open( const RString &sHost, int iPort, ConnectionType ct = CONN_TCP ) = 0;
|
||||
|
||||
/*
|
||||
* Close down a connection. Returns to STATE_IDLE.
|
||||
*/
|
||||
// Close down a connection. Returns to STATE_IDLE.
|
||||
virtual void Close() = 0;
|
||||
|
||||
/*
|
||||
* Wait for all sent data to be flushed, and shut down the connection.
|
||||
*/
|
||||
// Wait for all sent data to be flushed, and shut down the connection.
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
/*
|
||||
* Read data. Block until any data is received, then return all data
|
||||
* available. Return the number of bytes read. The return value will
|
||||
* always be >= 0, unless an error or cancellation occured.
|
||||
*/
|
||||
/* Read data. Block until any data is received, then return all data
|
||||
* available. Return the number of bytes read. The return value will always
|
||||
* be >= 0, unless an error or cancellation occured. */
|
||||
virtual int Read( void *pBuffer, size_t iSize ) = 0;
|
||||
|
||||
/*
|
||||
* Write data to the socket. (Design note: we always write all of the
|
||||
* data unless an error or cancellation occurs, and those states are checked
|
||||
* with GetState(). If that happens, the number of bytes written is
|
||||
* meaningless, since it may have simply been buffered and never sent. So,
|
||||
* this function returns no value.)
|
||||
*/
|
||||
/* Write data to the socket. (Design note: we always write all of the data
|
||||
* unless an error or cancellation occurs, and those states are checked
|
||||
* with GetState(). If that happens, the number of bytes written is
|
||||
* meaningless, since it may have simply been buffered and never sent.
|
||||
* So, this function returns no value.) */
|
||||
virtual void Write( const void *pBuffer, size_t iSize ) = 0;
|
||||
|
||||
/*
|
||||
* Cancel the connection. This operation can clear an error state, aborts
|
||||
/* Cancel the connection. This operation can clear an error state, aborts
|
||||
* any blocking calls, never fails, and will always result in the socket
|
||||
* being in STATE_CANCELLED.
|
||||
*
|
||||
* This is true even if the state was STATE_IDLE. For example, the user
|
||||
* This is true even if the state was STATE_IDLE. For example, the user
|
||||
* thread may be closing one connection on this object and opening another,
|
||||
* and the UI thread may call Cancel() in between these operations.
|
||||
*
|
||||
* This operation is threadsafe: a socket can be cancelled from any thread
|
||||
* while another thread is reading or writing. This is the only function
|
||||
* that can be called without serialization.
|
||||
*/
|
||||
* while another thread is reading or writing. This is the only function
|
||||
* that can be called without serialization. */
|
||||
virtual void Cancel() = 0;
|
||||
|
||||
enum State
|
||||
{
|
||||
/* The stream is closed, and is ready to be opened. */
|
||||
// The stream is closed, and is ready to be opened.
|
||||
STATE_IDLE,
|
||||
|
||||
/* The stream is connected and able to send and receive data. */
|
||||
// The stream is connected and able to send and receive data.
|
||||
STATE_CONNECTED,
|
||||
|
||||
/* The stream has been shut down on either end (either an EOF from
|
||||
@@ -157,7 +140,7 @@ private:
|
||||
HANDLE m_hResolve;
|
||||
HWND m_hResolveHwnd;
|
||||
|
||||
/* This event is signalled on cancellation, to wake us up if we're blocking. */
|
||||
// This event is signalled on cancellation, to wake us up if we're blocking.
|
||||
HANDLE m_hCompletionEvent;
|
||||
|
||||
RString m_sHost;
|
||||
@@ -181,7 +164,7 @@ NetworkStream *CreateNetworkStream()
|
||||
return new NetworkStream_Win32;
|
||||
}
|
||||
|
||||
/* WinSock implementation of NetworkStream. */
|
||||
/** @brief WinSock implementation of NetworkStream. */
|
||||
NetworkStream_Win32::NetworkStream_Win32():
|
||||
m_Mutex( "NetworkTCPSocket" )
|
||||
{
|
||||
@@ -202,7 +185,7 @@ NetworkStream_Win32::~NetworkStream_Win32()
|
||||
}
|
||||
|
||||
/* Wait for the specified network event to occur, or cancellation, whichever
|
||||
* happens first. On cancellation, return -1; on error, return the error
|
||||
* happens first. On cancellation, return -1; on error, return the error
|
||||
* code; on success, return 0. */
|
||||
int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent )
|
||||
{
|
||||
@@ -214,11 +197,11 @@ int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent )
|
||||
|
||||
m_Mutex.Lock();
|
||||
|
||||
/* This will reset the event. Do this while we hold the lock. */
|
||||
// This will reset the event. Do this while we hold the lock.
|
||||
WSANETWORKEVENTS events;
|
||||
WSAEnumNetworkEvents( m_Socket, m_hCompletionEvent, &events );
|
||||
|
||||
/* Was the event signalled due to cancellation? */
|
||||
// Was the event signalled due to cancellation?
|
||||
if( m_State == STATE_CANCELLED )
|
||||
{
|
||||
m_Mutex.Unlock();
|
||||
@@ -227,13 +210,13 @@ int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent )
|
||||
|
||||
m_Mutex.Unlock();
|
||||
|
||||
/* If the event didn't actually occur, keep waiting. */
|
||||
// If the event didn't actually occur, keep waiting.
|
||||
if( (events.lNetworkEvents & (1<<iEvent)) )
|
||||
return events.iErrorCode[iEvent];
|
||||
|
||||
/* If the socket was closed while we were waiting, stop. Note that when the
|
||||
/* If the socket was closed while we were waiting, stop. Note that when the
|
||||
* connection closes immediately after sending data, we'll receive both this
|
||||
* message and FD_READ at the same time. Only do this if the event we really
|
||||
* message and FD_READ at the same time. Only do this if the event we really
|
||||
* want hasn't happened yet. */
|
||||
if( (events.lNetworkEvents & (1<<FD_CLOSE_BIT)) )
|
||||
return WSAECONNRESET;
|
||||
@@ -242,8 +225,8 @@ int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent )
|
||||
|
||||
RString NetworkStream_Win32::WinSockErrorToString( int iError )
|
||||
{
|
||||
/* If iError is -1, we were cancelled and WaitForCompletionOrCancellation returned it. We won't
|
||||
* use the error string. */
|
||||
/* If iError is -1, we were cancelled and WaitForCompletionOrCancellation
|
||||
* returned it. We won't use the error string. */
|
||||
if( iError == -1 )
|
||||
return RString();
|
||||
|
||||
@@ -321,7 +304,7 @@ void NetworkStream_Win32::SetError( const RString &sError )
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
/* WSAAsyncGetHostByName returns events through a window. */
|
||||
// WSAAsyncGetHostByName returns events through a window.
|
||||
#include "MessageWindow.h"
|
||||
class ResolveMessageWindow: public MessageWindow
|
||||
{
|
||||
@@ -365,13 +348,13 @@ void NetworkStream_Win32::Open( const RString &sHost, int iPort, ConnectionType
|
||||
return;
|
||||
}
|
||||
|
||||
/* Always shut down a stream completely before reusing it. */
|
||||
// Always shut down a stream completely before reusing it.
|
||||
ASSERT_M( m_State == STATE_IDLE, ssprintf("%s:%i: %i", sHost.c_str(), iPort, m_State) );
|
||||
|
||||
m_sHost = sHost;
|
||||
m_iPort = iPort;
|
||||
|
||||
/* Look up the hostname. */
|
||||
|
||||
// Look up the hostname.
|
||||
hostent *pHost = NULL;
|
||||
char pBuf[MAXGETHOSTSTRUCT];
|
||||
{
|
||||
@@ -423,21 +406,21 @@ void NetworkStream_Win32::Open( const RString &sHost, int iPort, ConnectionType
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up the completion event to be signalled when these events occur. This
|
||||
* also sets the socket to nonblocking. */
|
||||
/* Set up the completion event to be signalled when these events occur.
|
||||
* This also sets the socket to nonblocking. */
|
||||
WSAEventSelect( m_Socket, m_hCompletionEvent, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE );
|
||||
|
||||
// fcntl( m_Socket, O_NONBLOCK, 1 );
|
||||
//fcntl( m_Socket, O_NONBLOCK, 1 );
|
||||
|
||||
/* Start opening the connection. */
|
||||
// Start opening the connection.
|
||||
int iResult = connect(m_Socket, (SOCKADDR *) &addr, sizeof(addr));
|
||||
|
||||
m_Mutex.Unlock();
|
||||
|
||||
/* We expect EINPROGRESS/WSAEWOULDBLOCK. */
|
||||
// We expect EINPROGRESS/WSAEWOULDBLOCK.
|
||||
if( iResult == SOCKET_ERROR )
|
||||
{
|
||||
/* Block until the connection attempt completes. */
|
||||
// Block until the connection attempt completes.
|
||||
int iError = WSAGetLastError();
|
||||
if( iError == WSAEWOULDBLOCK )
|
||||
iError = WaitForCompletionOrCancellation( FD_CONNECT_BIT );
|
||||
@@ -458,7 +441,7 @@ void NetworkStream_Win32::Close()
|
||||
return;
|
||||
|
||||
/* If we have an active, stable connection, make sure we flush any data
|
||||
* completely before closing. If you don't want to do this, call Cancel()
|
||||
* completely before closing. If you don't want to do this, call Cancel()
|
||||
* first. */
|
||||
Shutdown();
|
||||
|
||||
@@ -488,20 +471,20 @@ void NetworkStream_Win32::Cancel()
|
||||
{
|
||||
m_Mutex.Lock();
|
||||
|
||||
/* Mark cancellation. */
|
||||
// Mark cancellation.
|
||||
m_State = STATE_CANCELLED;
|
||||
|
||||
/* If resolving, abort the resolve. */
|
||||
// If resolving, abort the resolve.
|
||||
if( m_hResolve != NULL )
|
||||
{
|
||||
/* When we cancel the request, no message at all will be sent to the window,
|
||||
* so we need to do it ourself to inform it that it was cancelled. Be sure
|
||||
* so we need to do it ourself to inform it that it was cancelled. Be sure
|
||||
* to only do this on successful cancel. */
|
||||
if( WSACancelAsyncRequest(m_hResolve) == 0 )
|
||||
PostMessage( m_hResolveHwnd, WM_USER+1, 0, 0 );
|
||||
}
|
||||
|
||||
/* Break out if we're waiting in WaitForCompletionOrCancellation(). */
|
||||
// Break out if we're waiting in WaitForCompletionOrCancellation().
|
||||
SetEvent( m_hCompletionEvent );
|
||||
|
||||
m_Mutex.Unlock();
|
||||
@@ -527,14 +510,14 @@ int NetworkStream_Win32::Read( void *pBuffer, size_t iSize )
|
||||
|
||||
if( iRet == 0 )
|
||||
{
|
||||
/* We hit EOF. */
|
||||
// We hit EOF.
|
||||
break;
|
||||
}
|
||||
|
||||
int iError = WSAGetLastError();
|
||||
if( iError == WSAEWOULDBLOCK )
|
||||
{
|
||||
/* There's no date to read. If we've already received some data, return it. */
|
||||
// There's no date to read. If we've already received some data, return it.
|
||||
if( iRead > 0 )
|
||||
break;
|
||||
|
||||
@@ -543,12 +526,12 @@ int NetworkStream_Win32::Read( void *pBuffer, size_t iSize )
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the other side closed the connection, just return EOF. */
|
||||
// If the other side closed the connection, just return EOF.
|
||||
if( iError == WSAECONNRESET )
|
||||
break;
|
||||
|
||||
/* If we're cancelled or hit an error while reading, do return the data we managed
|
||||
* to get. Be sure not to overwrite CANCELLED with ERROR. */
|
||||
/* If we're cancelled or hit an error while reading, do return the data
|
||||
* we managed to get. Be sure not to overwrite CANCELLED with ERROR. */
|
||||
SetError( ssprintf("Error reading: %s", WinSockErrorToString(iError).c_str() ) );
|
||||
break;
|
||||
}
|
||||
@@ -586,10 +569,7 @@ void NetworkStream_Win32::Write( const void *pBuffer, size_t iSize )
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a set of data over HTTP, as a POST form.
|
||||
*/
|
||||
|
||||
/** @brief Send a set of data over HTTP, as a POST form. */
|
||||
NetworkPostData::NetworkPostData():
|
||||
m_Mutex( "NetworkPostData" )
|
||||
{
|
||||
@@ -601,10 +581,10 @@ NetworkPostData::~NetworkPostData()
|
||||
delete m_pStream;
|
||||
}
|
||||
|
||||
/* Create a MIME multipart data block from the given set of fields. */
|
||||
/** @brief Create a MIME multipart data block from the given set of fields. */
|
||||
void NetworkPostData::CreateMimeData( const map<RString,RString> &mapNameToData, RString &sOut, RString &sMimeBoundaryOut )
|
||||
{
|
||||
/* Find a non-conflicting mime boundary. */
|
||||
// Find a non-conflicting mime boundary.
|
||||
while(1)
|
||||
{
|
||||
sMimeBoundaryOut = ssprintf( "--%08i", rand() );
|
||||
@@ -655,19 +635,17 @@ void NetworkPostData::HttpThread()
|
||||
sBuf += sData;
|
||||
|
||||
/* The "progress" is currently faked; it shows when we've connected, and when
|
||||
* we've received data. We send and receive too little data to do more. */
|
||||
* we've received data. We send and receive too little data to do more. */
|
||||
SetProgress( 0 );
|
||||
|
||||
/*
|
||||
* Begin connecting.
|
||||
*/
|
||||
// Begin connecting.
|
||||
m_pStream->Open( m_sHost, m_iPort );
|
||||
SetProgress( 0.25f );
|
||||
|
||||
/* Send the form. */
|
||||
// Send the form.
|
||||
m_pStream->Write( sBuf.data(), sBuf.size() );
|
||||
|
||||
/* Read the result. */
|
||||
// Read the result.
|
||||
RString sResult;
|
||||
while( m_pStream->GetState() == NetworkStream::STATE_CONNECTED )
|
||||
{
|
||||
@@ -683,7 +661,7 @@ void NetworkPostData::HttpThread()
|
||||
|
||||
SetProgress( 1.0f );
|
||||
|
||||
/* Parse the results. */
|
||||
// Parse the results.
|
||||
int iStart = 0, iSize = -1;
|
||||
map<RString,RString> mapHeaders;
|
||||
while( 1 )
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
|
||||
class NetworkStream;
|
||||
|
||||
/*
|
||||
* Send a set of data over HTTP, as a POST form.
|
||||
*/
|
||||
// Send a set of data over HTTP, as a POST form.
|
||||
class NetworkPostData
|
||||
{
|
||||
public:
|
||||
@@ -17,13 +15,13 @@ public:
|
||||
|
||||
void SetData( const RString &sKey, const RString &sData );
|
||||
|
||||
/* For simplicity, we don't parse URLs here. */
|
||||
// For simplicity, we don't parse URLs here.
|
||||
void Start( const RString &sHost, int iPort, const RString &sPath );
|
||||
|
||||
/* Cancel the running operation, and close the thread. */
|
||||
// Cancel the running operation, and close the thread.
|
||||
void Cancel();
|
||||
|
||||
/* If the operation is unfinished, return false. Otherwise, close the thread and return true. */
|
||||
// If the operation is unfinished, return false. Otherwise, close the thread and return true.
|
||||
bool IsFinished();
|
||||
|
||||
RString GetStatus() const;
|
||||
@@ -43,7 +41,7 @@ private:
|
||||
RString m_sStatus;
|
||||
float m_fProgress;
|
||||
|
||||
/* When the thread exists, it owns the rest of the data, regardless of m_Mutex. */
|
||||
// When the thread exists, it owns the rest of the data, regardless of m_Mutex.
|
||||
map<RString, RString> m_Data;
|
||||
|
||||
bool m_bFinished;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
|
||||
static void LogVideoDriverInfo( VideoDriverInfo info )
|
||||
{
|
||||
LOG->Info( "Video driver: %s [%s]", info.sDescription.c_str(), info.sProvider.c_str() );
|
||||
@@ -200,7 +199,6 @@ static void GetWindowsVersionDebugInfo()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
RString Ver = ssprintf("Windows %i.%i (", ovi.dwMajorVersion, ovi.dwMinorVersion);
|
||||
if(ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
||||
{
|
||||
@@ -280,7 +278,6 @@ static void GetSoundDriverDebugInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SearchForDebugInfo()
|
||||
{
|
||||
GetWindowsVersionDebugInfo();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef DEBUG_INFO_HUNT_H
|
||||
#define DEBUG_INFO_HUNT_H
|
||||
|
||||
/* We want debug information; Windows makes us hunt for it. */
|
||||
/** @brief We want debug information; Windows makes us hunt for it. */
|
||||
void SearchForDebugInfo();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ static HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont)
|
||||
LOGFONT logFont = *lpLogFont;
|
||||
POINT pt;
|
||||
pt.y = ::GetDeviceCaps(hDC, LOGPIXELSY) * logFont.lfHeight;
|
||||
pt.y /= 720; // 72 points/inch, 10 decipoints/point
|
||||
pt.y /= 720; // 72 points/inch * 10 decipoints/point
|
||||
pt.x = 0;
|
||||
::DPtoLP(hDC, &pt, 1);
|
||||
POINT ptOrg = { 0, 0 };
|
||||
|
||||
@@ -14,11 +14,12 @@ RString werr_ssprintf( int err, const char *fmt, ... )
|
||||
0, err, 0, buf, sizeof(buf), NULL);
|
||||
#endif
|
||||
|
||||
/* Why is FormatMessage returning text ending with \r\n? */
|
||||
// Why is FormatMessage returning text ending with \r\n? (who? -aj)
|
||||
// Perhaps it's because you're on Windows, where newlines are \r\n. -aj
|
||||
RString text = buf;
|
||||
text.Replace( "\n", "" );
|
||||
text.Replace( "\r", " " ); /* foo\r\nbar -> foo bar */
|
||||
TrimRight( text ); /* "foo\r\n" -> "foo" */
|
||||
text.Replace( "\r", " " ); // foo\r\nbar -> foo bar
|
||||
TrimRight( text ); // "foo\r\n" -> "foo"
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
bool GetFileVersion( RString sFile, RString &sOut )
|
||||
{
|
||||
do {
|
||||
/* Cast away const to work around header bug in VC6. */
|
||||
// Cast away const to work around header bug in VC6.
|
||||
DWORD ignore;
|
||||
DWORD iSize = GetFileVersionInfoSize( const_cast<char *>(sFile.c_str()), &ignore );
|
||||
if( !iSize )
|
||||
break;
|
||||
|
||||
RString VersionBuffer( iSize, ' ' );
|
||||
/* Also VC6: */
|
||||
// Also VC6:
|
||||
if( !GetFileVersionInfo( const_cast<char *>(sFile.c_str()), NULL, iSize, VersionBuffer.GetBuffer() ) )
|
||||
break;
|
||||
|
||||
@@ -47,7 +47,7 @@ bool GetFileVersion( RString sFile, RString &sOut )
|
||||
sOut = RString( str, len-1 );
|
||||
} while(0);
|
||||
|
||||
/* Get the size and date. */
|
||||
// Get the size and date.
|
||||
struct stat st;
|
||||
if( stat( sFile, &st ) != -1 )
|
||||
{
|
||||
@@ -87,11 +87,12 @@ RString FindSystemFile( RString sFile )
|
||||
return RString();
|
||||
}
|
||||
|
||||
/* Get the full path of the process running in iProcessID. On error, false is
|
||||
/* Get the full path of the process running in iProcessID. On error, false is
|
||||
* returned and an error message is placed in sName. */
|
||||
bool GetProcessFileName( uint32_t iProcessID, RString &sName )
|
||||
{
|
||||
/* This method works in everything except for NT4, and only uses kernel32.lib functions. */
|
||||
/* This method works in everything except for NT4, and only uses
|
||||
* kernel32.lib functions. */
|
||||
do {
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, iProcessID );
|
||||
if( hSnap == NULL )
|
||||
@@ -115,7 +116,7 @@ bool GetProcessFileName( uint32_t iProcessID, RString &sName )
|
||||
sName = werr_ssprintf( GetLastError(), "Module32First" );
|
||||
} while(0);
|
||||
|
||||
/* This method only works in NT/2K/XP. */
|
||||
// This method only works in NT/2K/XP.
|
||||
do {
|
||||
static HINSTANCE hPSApi = NULL;
|
||||
typedef DWORD (WINAPI* pfnGetProcessImageFileNameA)(HANDLE hProcess, LPSTR lpImageFileName, DWORD nSize);
|
||||
|
||||
@@ -22,7 +22,6 @@ static LONG GetRegKey( HKEY key, RString subkey, LPTSTR retdata )
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool GotoURL( RString sUrl )
|
||||
{
|
||||
// First try ShellExecute()
|
||||
@@ -44,15 +43,15 @@ bool GotoURL( RString sUrl )
|
||||
char *szPos = strstr( key, "\"%1\"" );
|
||||
if( szPos == NULL )
|
||||
{
|
||||
// No quotes found. Check for %1 without quotes
|
||||
// No quotes found. Check for %1 without quotes
|
||||
szPos = strstr( key, "%1" );
|
||||
if( szPos == NULL )
|
||||
szPos = key+lstrlen(key)-1; // No parameter.
|
||||
if( szPos == NULL )
|
||||
szPos = key+lstrlen(key)-1; // No parameter.
|
||||
else
|
||||
*szPos = '\0'; // Remove the parameter
|
||||
*szPos = '\0'; // Remove the parameter
|
||||
}
|
||||
else
|
||||
*szPos = '\0'; // Remove the parameter
|
||||
*szPos = '\0'; // Remove the parameter
|
||||
|
||||
strcat( szPos, " " );
|
||||
strcat( szPos, sUrl );
|
||||
@@ -63,7 +62,7 @@ bool GotoURL( RString sUrl )
|
||||
/*
|
||||
* (c) 2002-2004 Chris Danford
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
@@ -73,7 +72,7 @@ bool GotoURL( RString sUrl )
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* Open URLs in a browser. */
|
||||
|
||||
#ifndef GOTO_URL_H
|
||||
#define GOTO_URL_H
|
||||
|
||||
/** @brief Open URLs in a browser. */
|
||||
bool GotoURL( RString sUrl );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
{
|
||||
CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );
|
||||
|
||||
/* Suppress autorun. */
|
||||
// Suppress autorun.
|
||||
if( msg == g_iQueryCancelAutoPlayMessage )
|
||||
return true;
|
||||
|
||||
@@ -80,8 +80,9 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
|
||||
if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode )
|
||||
{
|
||||
/* In OpenGL (not D3D), it's our job to unset and reset the full-screen video mode
|
||||
* when we focus changes, and to hide and show the window. Hiding is done in WM_KILLFOCUS,
|
||||
/* In OpenGL (not D3D), it's our job to unset and reset the
|
||||
* full-screen video mode when we focus changes, and to hide
|
||||
* and show the window. Hiding is done in WM_KILLFOCUS,
|
||||
* because that's where most other apps seem to do it. */
|
||||
if( g_bHasFocus && !bHadFocus )
|
||||
{
|
||||
@@ -101,7 +102,9 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
ShowWindow( g_hWndMain, SW_SHOWMINNOACTIVE );
|
||||
break;
|
||||
|
||||
/* Is there any reason we should care what size the user resizes the window to? */
|
||||
/* Is there any reason we should care what size the user resizes
|
||||
* the window to? (who? -aj)
|
||||
* Short answer: yes. -aj */
|
||||
// case WM_GETMINMAXINFO:
|
||||
|
||||
case WM_SETCURSOR:
|
||||
@@ -115,9 +118,9 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
case WM_SYSCOMMAND:
|
||||
switch( wParam&0xFFF0 )
|
||||
{
|
||||
case SC_MONITORPOWER:
|
||||
case SC_SCREENSAVE:
|
||||
return 0;
|
||||
case SC_MONITORPOWER:
|
||||
case SC_SCREENSAVE:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -133,7 +136,7 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
/* We handle all input ourself, via DirectInput. */
|
||||
// We handle all input ourself, via DirectInput.
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
@@ -143,8 +146,8 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
/* If we're fullscreen and don't have focus, our window is hidden, so GetClientRect
|
||||
* isn't meaningful. */
|
||||
/* If we're fullscreen and don't have focus, our window is hidden,
|
||||
* so GetClientRect isn't meaningful. */
|
||||
if( !g_CurrentParams.windowed && !g_bHasFocus )
|
||||
break;
|
||||
|
||||
@@ -192,8 +195,7 @@ static void AdjustVideoModeParams( VideoModeParams &p )
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* On a nForce 2 IGP on Windows 98, dm.dmDisplayFrequency sometimes
|
||||
/* On a nForce 2 IGP on Windows 98, dm.dmDisplayFrequency sometimes
|
||||
* (but not always) is 0.
|
||||
*
|
||||
* MSDN: When you call the EnumDisplaySettings function, the
|
||||
@@ -201,8 +203,7 @@ static void AdjustVideoModeParams( VideoModeParams &p )
|
||||
* These values represent the display hardware's default refresh rate.
|
||||
* This default rate is typically set by switches on a display card or
|
||||
* computer motherboard, or by a configuration program that does not
|
||||
* use Win32 display functions such as ChangeDisplaySettings.
|
||||
*/
|
||||
* use Win32 display functions such as ChangeDisplaySettings. */
|
||||
if( !(dm.dmFields & DM_DISPLAYFREQUENCY) ||
|
||||
dm.dmDisplayFrequency == 0 ||
|
||||
dm.dmDisplayFrequency == 1 )
|
||||
@@ -222,7 +223,7 @@ RString GraphicsWindow::SetScreenMode( const VideoModeParams &p )
|
||||
{
|
||||
if( p.windowed )
|
||||
{
|
||||
/* We're going windowed. If we were previously fullscreen, reset. */
|
||||
// We're going windowed. If we were previously fullscreen, reset.
|
||||
ChangeDisplaySettings( NULL, 0 );
|
||||
|
||||
return RString();
|
||||
@@ -250,7 +251,7 @@ RString GraphicsWindow::SetScreenMode( const VideoModeParams &p )
|
||||
ret = ChangeDisplaySettings( &DevMode, CDS_FULLSCREEN );
|
||||
}
|
||||
|
||||
/* XXX: append error */
|
||||
// XXX: append error
|
||||
if( ret != DISP_CHANGE_SUCCESSFUL )
|
||||
return "Couldn't set screen mode";
|
||||
|
||||
@@ -285,12 +286,12 @@ void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForce
|
||||
if( hWnd == NULL )
|
||||
RageException::Throw( "%s", werr_ssprintf( GetLastError(), "CreateWindow" ).c_str() );
|
||||
|
||||
/* If an old window exists, transfer focus to the new window before deleting
|
||||
* it, or some other window may temporarily get focus, which can cause it
|
||||
* to be resized. */
|
||||
/* If an old window exists, transfer focus to the new window before
|
||||
* deleting it, or some other window may temporarily get focus, which
|
||||
* can cause it to be resized. */
|
||||
if( g_hWndMain != NULL )
|
||||
{
|
||||
/* While we change to the new window, don't do ChangeDisplaySettings in WM_ACTIVATE. */
|
||||
// While we change to the new window, don't do ChangeDisplaySettings in WM_ACTIVATE.
|
||||
g_bRecreatingVideoMode = true;
|
||||
SetForegroundWindow( hWnd );
|
||||
g_bRecreatingVideoMode = false;
|
||||
@@ -327,7 +328,7 @@ void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForce
|
||||
SetClassLong( g_hWndMain, GCL_HICON, (LONG) g_hIcon );
|
||||
|
||||
/* The window style may change as a result of switching to or from fullscreen;
|
||||
* apply it. Don't change the WS_VISIBLE bit. */
|
||||
* apply it. Don't change the WS_VISIBLE bit. */
|
||||
int iWindowStyle = GetWindowStyle( p.windowed );
|
||||
if( GetWindowLong( g_hWndMain, GWL_STYLE ) & WS_VISIBLE )
|
||||
iWindowStyle |= WS_VISIBLE;
|
||||
@@ -342,7 +343,7 @@ void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForce
|
||||
const int iWidth = WindowRect.right - WindowRect.left;
|
||||
const int iHeight = WindowRect.bottom - WindowRect.top;
|
||||
|
||||
/* If windowed, center the window. */
|
||||
// If windowed, center the window.
|
||||
int x = 0, y = 0;
|
||||
if( p.windowed )
|
||||
{
|
||||
@@ -350,8 +351,8 @@ void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForce
|
||||
y = GetSystemMetrics(SM_CYSCREEN)/2-iHeight/2;
|
||||
}
|
||||
|
||||
/* Move and resize the window. SWP_FRAMECHANGED causes the above SetWindowLong
|
||||
* to take effect. */
|
||||
/* Move and resize the window. SWP_FRAMECHANGED causes the above
|
||||
* SetWindowLong to take effect. */
|
||||
if( !SetWindowPos( g_hWndMain, HWND_NOTOPMOST, x, y, iWidth, iHeight, SWP_FRAMECHANGED|SWP_SHOWWINDOW ) )
|
||||
LOG->Warn( "%s", werr_ssprintf( GetLastError(), "SetWindowPos" ).c_str() );
|
||||
|
||||
@@ -368,7 +369,7 @@ void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForce
|
||||
}
|
||||
}
|
||||
|
||||
/* Shut down the window, but don't reset the video mode. */
|
||||
/** @brief Shut down the window, but don't reset the video mode. */
|
||||
void GraphicsWindow::DestroyGraphicsWindow()
|
||||
{
|
||||
if( g_HDC != NULL )
|
||||
@@ -410,7 +411,7 @@ void GraphicsWindow::DestroyGraphicsWindow()
|
||||
|
||||
void GraphicsWindow::Initialize( bool bD3D )
|
||||
{
|
||||
/* A few things need to be handled differently for D3D. */
|
||||
// A few things need to be handled differently for D3D.
|
||||
g_bD3D = bD3D;
|
||||
|
||||
AppInstance inst;
|
||||
@@ -461,13 +462,10 @@ void GraphicsWindow::Shutdown()
|
||||
{
|
||||
DestroyGraphicsWindow();
|
||||
|
||||
/*
|
||||
* Return to the desktop resolution, if needed.
|
||||
*
|
||||
* It'd be nice to not do this: Windows will do it when we quit, and if we're
|
||||
* shutting down OpenGL to try D3D, this will cause extra mode switches. However,
|
||||
* we need to do this before displaying dialogs.
|
||||
*/
|
||||
/* Return to the desktop resolution, if needed.
|
||||
* It'd be nice to not do this: Windows will do it when we quit, and if
|
||||
* we're shutting down OpenGL to try D3D, this will cause extra mode
|
||||
* switches. However, we need to do this before displaying dialogs. */
|
||||
ChangeDisplaySettings( NULL, 0 );
|
||||
|
||||
AppInstance inst;
|
||||
@@ -500,7 +498,7 @@ void GraphicsWindow::Update()
|
||||
{
|
||||
//LOG->Warn( "Changing resolution" );
|
||||
|
||||
/* Let DISPLAY know that our resolution has changed. (Note that ResolutionChanged()
|
||||
/* Let DISPLAY know that our resolution has changed. (Note that ResolutionChanged()
|
||||
* can come back here, so reset g_bResolutionChanged first.) */
|
||||
g_bResolutionChanged = false;
|
||||
DISPLAY->ResolutionChanged();
|
||||
@@ -528,7 +526,6 @@ void GraphicsWindow::GetDisplayResolutions( DisplayResolutions &out )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (c) 2004 Glenn Maynard
|
||||
* All rights reserved.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* GraphicsWindow - Sets up a window for OpenGL/D3D. */
|
||||
|
||||
#ifndef GRAPHICS_WINDOW_H
|
||||
#define GRAPHICS_WINDOW_H
|
||||
|
||||
@@ -8,19 +6,25 @@
|
||||
class VideoModeParams;
|
||||
class DisplayResolution;
|
||||
|
||||
/** @brief Sets up a window for OpenGL/D3D. */
|
||||
namespace GraphicsWindow
|
||||
{
|
||||
/* Set up, and create a hidden window. This only needs to be called once. */
|
||||
/** @brief Set up, and create a hidden window.
|
||||
*
|
||||
* This only needs to be called once. */
|
||||
void Initialize( bool bD3D );
|
||||
|
||||
/* Shut down completely. */
|
||||
/** @brief Shut down completely. */
|
||||
void Shutdown();
|
||||
|
||||
/* Set the display mode. p will not be second-guessed, except to try disabling
|
||||
* the refresh rate setting. */
|
||||
/** @brief Set the display mode.
|
||||
*
|
||||
* p will not be second-guessed, except to try disabling the refresh rate setting. */
|
||||
RString SetScreenMode( const VideoModeParams &p );
|
||||
|
||||
/* Create the window. This also updates VideoModeParams (returned by GetParams). */
|
||||
/** @brief Create the window.
|
||||
*
|
||||
* This also updates VideoModeParams (returned by GetParams). */
|
||||
void CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow = false );
|
||||
void DestroyGraphicsWindow();
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
#pragma warning (disable : 4201) // nonstandard extension used : nameless struct/union (Windows headers do this)
|
||||
#pragma warning (disable : 4786) // turn off broken debugger warning
|
||||
#pragma warning (disable : 4512) // assignment operator could not be generated (so?)
|
||||
/* "unreachable code". This warning crops up in incorrect places (end of do ... while(0)
|
||||
/* "unreachable code". This warning crops up in incorrect places (end of do ... while(0)
|
||||
* blocks, try/catch blocks), and I've never found it to be useful. */
|
||||
#pragma warning (disable : 4702) // assignment operator could not be generated (so?)
|
||||
/* "unreferenced formal parameter"; we *want* that in many cases */
|
||||
// "unreferenced formal parameter"; we *want* that in many cases
|
||||
#pragma warning (disable : 4100)
|
||||
/* "case 'aaa' is not a valid value for switch of enum 'bbb'
|
||||
* Actually, this is a valid warning, but we do it all over the
|
||||
* place, eg. with ScreenMessages. Those should be fixed, but later. XXX */
|
||||
* place, eg. with ScreenMessages. Those should be fixed, but later. XXX */
|
||||
#pragma warning (disable : 4063)
|
||||
#pragma warning (disable : 4127)
|
||||
#pragma warning (disable : 4786) /* VC6: identifier was truncated to '255' characters in the debug information */
|
||||
@@ -44,43 +44,43 @@
|
||||
#pragma warning (disable : 4244) // converting of data = possible data loss. (This pragma should eventually go away)
|
||||
#pragma warning (disable : 4355) // 'this' : used in base member initializer list
|
||||
|
||||
/* Fix VC breakage. */
|
||||
// Fix VC breakage.
|
||||
#define PATH_MAX _MAX_PATH
|
||||
|
||||
/* Disable false deprecation warnings in VC2005. */
|
||||
// Disable false deprecation warnings in VC2005.
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _SCL_SECURE_NO_DEPRECATE
|
||||
|
||||
/* Disable false deprecation warnings in VC2008. */
|
||||
// Disable false deprecation warnings in VC2008.
|
||||
#define _CRT_NONSTDC_NO_WARNINGS
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400 // this is needed in VC8 but breaks VC7
|
||||
#define _HAS_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
/* Don't include windows.h everywhere; when we do eventually include it, use these: */
|
||||
// Don't include windows.h everywhere; when we do eventually include it, use these:
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
|
||||
/* Pull in NT-only definitions. Note that we support Win98 and WinME; you can make
|
||||
* NT calls, but be sure to fall back on 9x if they're not supported. */
|
||||
/* Pull in NT-only definitions. Note that we support Win98 and WinME; you can
|
||||
* make NT calls, but be sure to fall back on 9x if they're not supported. */
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#define _WIN32_IE 0x0400
|
||||
|
||||
/* If this isn't defined to 0, VC fails to define things like stat and alloca. */
|
||||
// If this isn't defined to 0, VC fails to define things like stat and alloca.
|
||||
#define __STDC__ 0
|
||||
|
||||
#endif
|
||||
|
||||
#include <direct.h> /* has stuff that should be in unistd.h */
|
||||
#include <wchar.h> /* needs to be included before our fixes below */
|
||||
#include <direct.h> // has stuff that should be in unistd.h
|
||||
#include <wchar.h> // needs to be included before our fixes below
|
||||
|
||||
#define lstat stat
|
||||
#define fsync _commit
|
||||
#define isnan _isnan
|
||||
#define isfinite _finite
|
||||
|
||||
/* mkdir is missing the mode arg */
|
||||
// mkdir is missing the mode arg
|
||||
#define mkdir(p,m) mkdir(p)
|
||||
|
||||
typedef time_t time_t;
|
||||
@@ -92,9 +92,7 @@ struct tm *my_gmtime_r( const time_t *timep, struct tm *result );
|
||||
void my_usleep( unsigned long usec );
|
||||
#define usleep my_usleep
|
||||
|
||||
|
||||
|
||||
/* Missing stdint types: */
|
||||
// Missing stdint types:
|
||||
#if !defined(__MINGW32__) // MinGW headers define these for us
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
@@ -116,9 +114,9 @@ static inline int64_t llabs( int64_t i ) { return i >= 0? i: -i; }
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
#define NOMINMAX /* make sure Windows doesn't try to define this */
|
||||
#define NOMINMAX // make sure Windows doesn't try to define this
|
||||
|
||||
/* Windows is missing some basic math functions: */
|
||||
// Windows is missing some basic math functions:
|
||||
// But MinGW isn't.
|
||||
#if !defined(__MINGW32__)
|
||||
#define NEED_TRUNCF
|
||||
@@ -132,7 +130,7 @@ static inline int64_t llabs( int64_t i ) { return i >= 0? i: -i; }
|
||||
inline long int lrintf( float f )
|
||||
{
|
||||
int retval;
|
||||
|
||||
|
||||
_asm fld f;
|
||||
_asm fistp retval;
|
||||
|
||||
@@ -140,11 +138,11 @@ inline long int lrintf( float f )
|
||||
}
|
||||
#endif
|
||||
|
||||
/* For RageLog. */
|
||||
// For RageLog.
|
||||
#define HAVE_VERSION_INFO
|
||||
|
||||
/* We implement the crash handler interface (though that interface isn't completely
|
||||
* uniform across platforms yet). */
|
||||
/* We implement the crash handler interface (though that interface isn't
|
||||
* completely uniform across platforms yet). */
|
||||
#if !defined(_XBOX) && !defined(SMPACKAGE)
|
||||
#define CRASH_HANDLER
|
||||
#endif
|
||||
@@ -165,7 +163,6 @@ inline long int lrintf( float f )
|
||||
#include "ArchUtils/Xbox/arch_setup.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__) // It might be MinGW or Cygwin(?)
|
||||
#include "archutils/Common/gcc_byte_swaps.h"
|
||||
#else // XXX: Should we test for MSVC?
|
||||
|
||||
Reference in New Issue
Block a user