smsvn -> ssc-hg glue: rearrange directory structure

This commit is contained in:
Devin J. Pohly
2013-06-10 15:38:43 -04:00
parent 51576d5942
commit 80057f53cd
3362 changed files with 0 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
#include "global.h"
#include "AppInstance.h"
AppInstance::AppInstance()
{
/* 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
* will still work without one (but may be missing graphics); that's OK. */
}
AppInstance::~AppInstance()
{
if(h)
FreeLibrary(h);
}
/*
* (c) 2002-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+47
View File
@@ -0,0 +1,47 @@
/* AppInstance - get an HINSTANCE for starting dialog boxes. */
#ifndef APP_INSTANCE_H
#define APP_INSTANCE_H
#if !defined(_XBOX)
# include "windows.h"
#endif
class AppInstance
{
public:
AppInstance();
~AppInstance();
HINSTANCE Get() const { return h; }
operator HINSTANCE () const { return h; }
private:
HINSTANCE h;
};
#endif
/*
* (c) 2002-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+74
View File
@@ -0,0 +1,74 @@
#include "global.h"
#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. */
int GetWin32CmdLine( char** &argv )
{
char *pCmdLine = GetCommandLine();
int argc = 0;
argv = NULL;
int i = 0;
while( pCmdLine[i] )
{
argv = (char **) realloc( argv, (argc+1) * sizeof(char *) );
argv[argc] = pCmdLine+i;
++argc;
/* Skip to the end of this argument. */
while( pCmdLine[i] && pCmdLine[i] != ' ' )
{
if( pCmdLine[i] == '"' )
{
/* Erase the quote. */
memmove( pCmdLine+i, pCmdLine+i+1, strlen(pCmdLine+i+1)+1 );
/* Skip to the close quote. */
while( pCmdLine[i] && pCmdLine[i] != '"' )
++i;
/* Erase the close quote. */
if( pCmdLine[i] == '"' )
memmove( pCmdLine+i, pCmdLine+i+1, strlen(pCmdLine+i+1)+1 );
}
else
++i;
}
if( pCmdLine[i] == ' ' )
{
pCmdLine[i] = '\0';
++i;
}
}
return argc;
}
/*
* (c) 2006 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+33
View File
@@ -0,0 +1,33 @@
/* Helper to simulate standard argv[] semantics with WinMain. */
#ifndef CommandLine_H
#define CommandLine_H
int GetWin32CmdLine( char** &argv );
#endif
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+639
View File
@@ -0,0 +1,639 @@
#include "global.h"
// DO NOT USE stdio.h! printf() calls malloc()!
//#include <stdio.h>
#include <windows.h>
#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 "RestartProgram.h"
// WARNING: This is called from crash-time conditions! No malloc() or new!!!
#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;
GetModuleFileName(NULL, tbuf, sizeof tbuf);
GetFullPathName(tbuf, bufsiz, buf, &pszFile);
strcpy(pszFile, fn);
}
///////////////////////////////////////////////////////////////////////////
static const struct ExceptionLookup {
DWORD code;
const char *name;
} exceptions[]={
{ EXCEPTION_ACCESS_VIOLATION, "Access Violation" },
{ EXCEPTION_BREAKPOINT, "Breakpoint" },
{ EXCEPTION_FLT_DENORMAL_OPERAND, "FP Denormal Operand" },
{ EXCEPTION_FLT_DIVIDE_BY_ZERO, "FP Divide-by-Zero" },
{ EXCEPTION_FLT_INEXACT_RESULT, "FP Inexact Result" },
{ EXCEPTION_FLT_INVALID_OPERATION, "FP Invalid Operation" },
{ EXCEPTION_FLT_OVERFLOW, "FP Overflow", },
{ EXCEPTION_FLT_STACK_CHECK, "FP Stack Check", },
{ EXCEPTION_FLT_UNDERFLOW, "FP Underflow", },
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer Divide-by-Zero", },
{ EXCEPTION_INT_OVERFLOW, "Integer Overflow", },
{ EXCEPTION_PRIV_INSTRUCTION, "Privileged Instruction", },
{ EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal instruction" },
{ EXCEPTION_INVALID_HANDLE, "Invalid handle" },
{ EXCEPTION_STACK_OVERFLOW, "Stack overflow" },
{ 0xe06d7363, "Unhandled Microsoft C++ Exception", },
{ NULL },
};
static const char *LookupException( DWORD code )
{
for( int i = 0; exceptions[i].code; ++i )
if( exceptions[i].code == code )
return exceptions[i].name;
return NULL;
}
static CrashInfo g_CrashInfo;
static void GetReason( const EXCEPTION_RECORD *pRecord, CrashInfo *crash )
{
// fill out bomb reason
const char *reason = LookupException( pRecord->ExceptionCode );
if( reason == NULL )
wsprintf( crash->m_CrashReason, "unknown exception 0x%08lx", pRecord->ExceptionCode );
else
strcpy( crash->m_CrashReason, reason );
}
static HWND g_hForegroundWnd = NULL;
void CrashHandler::SetForegroundWindow( HWND hWnd )
{
g_hForegroundWnd = hWnd;
}
void WriteToChild( HANDLE hPipe, const void *pData, size_t iSize )
{
while( iSize )
{
DWORD iActual;
if( !WriteFile(hPipe, pData, iSize, &iActual, NULL) )
return;
iSize -= iActual;
}
}
/* 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 )
{
char cwd[MAX_PATH];
SpliceProgramPath( cwd, MAX_PATH, "" );
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.dwFlags |= STARTF_USESTDHANDLES;
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = NULL;
CreatePipe( &si.hStdInput, &hToStdin, &sa, 0 );
CreatePipe( &hFromStdout, &si.hStdOutput, &sa, 0 );
SetHandleInformation( hToStdin, HANDLE_FLAG_INHERIT, 0 );
SetHandleInformation( hFromStdout, HANDLE_FLAG_INHERIT, 0 );
}
char szBuf[256] = "";
GetModuleFileName( NULL, szBuf, MAX_PATH );
strcat( szBuf, " " );
strcat( szBuf, CHILD_MAGIC_PARAMETER );
PROCESS_INFORMATION pi;
int iRet = CreateProcess(
NULL, // pointer to name of executable module
szBuf, // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
true, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
cwd, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
CloseHandle( si.hStdInput );
CloseHandle( si.hStdOutput );
if( !iRet )
{
CloseHandle( hToStdin );
CloseHandle( hFromStdout );
return false;
}
hProcess = pi.hProcess;
return true;
}
static const char *CrashGetModuleBaseName(HMODULE hmod, char *pszBaseName)
{
char szPath1[MAX_PATH];
char szPath2[MAX_PATH];
__try {
if( !GetModuleFileName(hmod, szPath1, sizeof(szPath1)) )
return NULL;
char *pszFile;
DWORD dw = GetFullPathName( szPath1, sizeof(szPath2), szPath2, &pszFile );
if( !dw || dw > sizeof(szPath2) )
return NULL;
strcpy( pszBaseName, pszFile );
pszFile = pszBaseName;
char *period = NULL;
while( *pszFile++ )
if( pszFile[-1]=='.' )
period = pszFile-1;
if( period )
*period = 0;
} __except(1) {
return NULL;
}
return pszBaseName;
}
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. */
{
HANDLE hTargetHandle;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentProcess(),
hProcess,
&hTargetHandle,
0,
false,
DUPLICATE_SAME_ACCESS
);
WriteToChild( hToStdin, &hTargetHandle, sizeof(hTargetHandle) );
}
/* 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 );
/* 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;
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 );
/* 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. */
while(1)
{
/* Ugly: the new process can't execute GetModuleFileName on this process,
* since GetModuleFileNameEx might not be available. Run the requests here. */
HMODULE hMod;
DWORD iActual;
if( !ReadFile( hFromStdout, &hMod, sizeof(hMod), &iActual, NULL) )
break;
char szName[MAX_PATH];
if( !CrashGetModuleBaseName(hMod, szName) )
strcpy( szName, "???" );
iSize = strlen( szName );
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
WriteToChild( hToStdin, szName, iSize );
}
}
static long MainExceptionHandler( EXCEPTION_POINTERS *pExc )
{
/* Flush the log 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. */
// 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.
*
* 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. */
switch( pExc->ExceptionRecord->ExceptionCode )
{
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_FLT_INEXACT_RESULT:
pExc->ContextRecord->FloatSave.ControlWord |= 0x3F;
return EXCEPTION_CONTINUE_EXECUTION;
}
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. */
SetUnhandledExceptionFilter(NULL);
MessageBox( NULL,
InHere == 1?
"The error reporting interface has crashed.\n":
"The error reporting interface has crashed. However, crashinfo.txt was"
"written successfully to the program directory.\n",
"Fatal Error", MB_OK );
#ifdef DEBUG
DebugBreak();
#endif
return EXCEPTION_EXECUTE_HANDLER;
}
++InHere;
/////////////////////////
RageThread::HaltAllThreads( false );
if( !g_CrashInfo.m_CrashReason[0] )
GetReason( pExc->ExceptionRecord, &g_CrashInfo );
CrashHandler::do_backtrace( g_CrashInfo.m_BacktracePointers, BACKTRACE_MAX_SIZE, GetCurrentProcess(), GetCurrentThread(), pExc->ContextRecord );
RunChild();
++InHere;
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. */
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. */
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. */
RageThread::HaltAllThreads( true );
ChangeDisplaySettings( NULL, 0 );
}
InHere = false;
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. */
TerminateProcess( GetCurrentProcess(), 0 );
return EXCEPTION_EXECUTE_HANDLER;
}
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. */
int iSize = 1024*32;
char *pStack = (char *) VirtualAlloc( NULL, iSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
pStack += iSize;
_asm mov esp, pStack;
return MainExceptionHandler( pExc );
}
//////////////////////////////////////////////////////////////////////////////
static bool IsValidCall(char *buf, int len)
{
// Permissible CALL sequences that we care about:
//
// E8 xx xx xx xx CALL near relative
// FF (group 2) CALL near absolute indirect
//
// Minimum sequence is 2 bytes (call eax).
// Maximum sequence is 7 bytes (call dword ptr [eax+disp32]).
if (len >= 5 && buf[-5] == '\xe8')
return true;
// FF 14 xx CALL [reg32+reg32*scale]
if (len >= 3 && buf[-3] == '\xff' && buf[-2]=='\x14')
return true;
// FF 15 xx xx xx xx CALL disp32
if (len >= 6 && buf[-6] == '\xff' && buf[-5]=='\x15')
return true;
// FF 00-3F(!14/15) CALL [reg32]
if (len >= 2 && buf[-2] == '\xff' && (unsigned char)buf[-1] < '\x40')
return true;
// FF D0-D7 CALL reg32
if (len >= 2 && buf[-2] == '\xff' && (buf[-1]&0xF8) == '\xd0')
return true;
// FF 50-57 xx CALL [reg32+reg32*scale+disp8]
if (len >= 3 && buf[-3] == '\xff' && (buf[-2]&0xF8) == '\x50')
return true;
// FF 90-97 xx xx xx xx xx CALL [reg32+reg32*scale+disp32]
if (len >= 7 && buf[-7] == '\xff' && (buf[-6]&0xF8) == '\x90')
return true;
return false;
}
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.'
VirtualQuery(IsExecutableProtection, &meminfo, sizeof meminfo);
switch((unsigned char)dwProtect) {
case PAGE_READONLY: // *sigh* Win9x...
case PAGE_READWRITE: // *sigh*
return meminfo.Protect==PAGE_READONLY || meminfo.Protect==PAGE_READWRITE;
case PAGE_EXECUTE:
case PAGE_EXECUTE_READ:
case PAGE_EXECUTE_READWRITE:
case PAGE_EXECUTE_WRITECOPY:
return true;
}
return false;
}
static bool PointsToValidCall( unsigned long ptr )
{
char buf[7];
int len = 7;
memset( buf, 0, sizeof(buf) );
while(len > 0 && !ReadProcessMemory(GetCurrentProcess(), (void *)(ptr-len), buf+7-len, len, NULL))
--len;
return IsValidCall(buf+7, len);
}
void CrashHandler::do_backtrace( const void **buf, size_t size,
HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext )
{
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. */
if( buf+1 != pLast && pContext->Eip != NULL )
{
*buf = (void *) pContext->Eip;
++buf;
}
// Retrieve stack pointers.
const char *pStackBase;
{
LDT_ENTRY sel;
if( !GetThreadSelectorEntry( hThread, pContext->SegFs, &sel ) )
{
*buf = NULL;
return;
}
const NT_TIB *tib = (NT_TIB *) ((sel.HighWord.Bits.BaseHi<<24)+(sel.HighWord.Bits.BaseMid<<16)+sel.BaseLow);
const NT_TIB *pTib = tib->Self;
pStackBase = (char *)pTib->StackBase;
}
// Walk up the stack.
const char *lpAddr = (const char *)pContext->Esp;
const void *data = (void *) pContext->Eip;
do {
if( buf == pLast )
break;
bool fValid = true;
/* The first entry is usually EIP. We already logged it; skip it, so we don't always
* show the first frame twice. */
if( bFirst && data == (void *) pContext->Eip )
fValid = false;
bFirst = false;
{
MEMORY_BASIC_INFORMATION meminfo;
VirtualQuery((void *)data, &meminfo, sizeof meminfo);
if (!IsExecutableProtection(meminfo.Protect) || meminfo.State!=MEM_COMMIT)
fValid = false;
if ( data != (void *) pContext->Eip && !PointsToValidCall((unsigned long)data) )
fValid = false;
}
if( fValid )
{
*buf = data;
++buf;
}
if (lpAddr >= pStackBase)
break;
lpAddr += 4;
} while( ReadProcessMemory(hProcess, lpAddr-4, &data, 4, NULL));
*buf = NULL;
}
/* Trigger the crash handler. This works even in the debugger. */
static void NORETURN debug_crash()
{
__try {
__asm xor ebx,ebx
__asm mov eax,dword ptr [ebx]
// __asm mov dword ptr [ebx],eax
// __asm lock add dword ptr cs:[00000000h], 12345678h
} __except( CrashHandler::ExceptionHandler((EXCEPTION_POINTERS*)_exception_info()) ) {
}
}
/* 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.) */
RageThread::HaltAllThreads( false );
if( iID == GetInvalidThreadId() )
{
/* Backtrace all threads. */
int iCnt = 0;
for( int i = 0; RageThread::EnumThreadIDs(i, iID); ++i )
{
if( iID == GetInvalidThreadId() )
continue;
if( iID == GetCurrentThreadId() )
continue;
const HANDLE hThread = Win32ThreadIdToHandle( iID );
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
if( !GetThreadContext( hThread, &context ) )
wsprintf( g_CrashInfo.m_CrashReason + strlen(g_CrashInfo.m_CrashReason),
"; GetThreadContext(%x) failed", (int) hThread );
else
{
static const void *BacktracePointers[BACKTRACE_MAX_SIZE];
do_backtrace( g_CrashInfo.m_AlternateThreadBacktrace[iCnt], BACKTRACE_MAX_SIZE, GetCurrentProcess(), hThread, &context );
const char *pName = RageThread::GetThreadNameByID( iID );
strncpy( g_CrashInfo.m_AlternateThreadName[iCnt], pName? pName:"???", sizeof(g_CrashInfo.m_AlternateThreadName[iCnt])-1 );
++iCnt;
}
if( iCnt == CrashInfo::MAX_BACKTRACE_THREADS )
break;
}
} else {
const HANDLE hThread = Win32ThreadIdToHandle( iID );
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
if( !GetThreadContext( hThread, &context ) )
strcat( g_CrashInfo.m_CrashReason, "(GetThreadContext failed)" );
else
{
static const void *BacktracePointers[BACKTRACE_MAX_SIZE];
do_backtrace( g_CrashInfo.m_AlternateThreadBacktrace[0], BACKTRACE_MAX_SIZE, GetCurrentProcess(), hThread, &context );
const char *pName = RageThread::GetThreadNameByID( iID );
strncpy( g_CrashInfo.m_AlternateThreadName[0], pName? pName:"???", sizeof(g_CrashInfo.m_AlternateThreadName[0])-1 );
}
}
debug_crash();
}
void CrashHandler::ForceCrash( const char *reason )
{
strncpy( g_CrashInfo.m_CrashReason, reason, sizeof(g_CrashInfo.m_CrashReason) );
g_CrashInfo.m_CrashReason[ sizeof(g_CrashInfo.m_CrashReason)-1 ] = 0;
debug_crash();
}
/*
* (c) 1998-2001 Avery Lee
* (c) 2003-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+48
View File
@@ -0,0 +1,48 @@
/* Win32 crash handling. */
#ifndef CRASH_H
#define CRASH_H
#include <windows.h>
namespace CrashHandler
{
extern long __stdcall ExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo);
void do_backtrace( const void **buf, size_t size, HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext );
void SymLookup( const void *ptr, char *buf );
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. */
void SetForegroundWindow( HWND hWnd );
void CrashHandlerHandleArgs( int argc, char* argv[] );
};
#endif
/*
* (c) 1998-2001 Avery Lee
* (c) 2003-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+903
View File
@@ -0,0 +1,903 @@
#include "global.h"
#include "CrashHandlerInternal.h"
#include "Crash.h"
#include <errno.h>
#include <windows.h>
#include <commctrl.h>
#include "archutils/Win32/ddk/dbghelp.h"
#include <io.h>
#include <fcntl.h>
#include "arch/ArchHooks/ArchHooks.h"
#include "archutils/Win32/WindowsResources.h"
#include "archutils/Win32/DialogUtil.h"
#include "archutils/Win32/ErrorStrings.h"
#include "archutils/Win32/GotoURL.h"
#include "archutils/Win32/RestartProgram.h"
#include "archutils/Win32/CrashHandlerNetworking.h"
#include "archutils/Win32/WindowsDialogBox.h"
#include "ProductInfo.h"
#include "RageUtil.h"
#include "XmlFile.h"
#include "XmlFileUtil.h"
#include "LocalizedString.h"
#include "RageFileDriverDeflate.h"
#if defined(_MSC_VER)
#pragma comment(lib, "archutils/Win32/ddk/dbghelp.lib")
#endif
extern unsigned long version_num;
extern const char *const version_time;
// VDI symbol lookup:
namespace VDDebugInfo
{
struct Context
{
Context() { pRVAHeap=NULL; }
bool Loaded() const { return pRVAHeap != NULL; }
RString sRawBlock;
int nBuildNumber;
const unsigned char *pRVAHeap;
unsigned nFirstRVA;
const char *pFuncNameHeap;
const unsigned long (*pSegments)[2];
int nSegments;
char sFilename[1024];
RString sError;
};
static void GetVDIPath( char *buf, int bufsiz )
{
GetModuleFileName( NULL, buf, bufsiz );
buf[bufsiz-5] = 0;
char *p = strrchr( buf, '.' );
if( p )
strcpy( p, ".vdi" );
else
strcat( buf, ".vdi" );
}
bool VDDebugInfoInitFromMemory( Context *pctx )
{
if( pctx->sRawBlock[0] == '\x1f' &&
pctx->sRawBlock[1] == '\x8b' )
{
RString sBufOut;
RString sError;
if( !GunzipString(pctx->sRawBlock, sBufOut, sError) )
{
pctx->sError = werr_ssprintf( GetLastError(), "VDI error: %s", sError.c_str() );
return false;
}
pctx->sRawBlock = sBufOut;
}
const unsigned char *src = (const unsigned char *) pctx->sRawBlock.data();
pctx->pRVAHeap = NULL;
static const char *header = "symbolic debug information";
if( memcmp(src, header, strlen(header)) )
{
pctx->sError = "header doesn't match";
return false;
}
// Extract fields
src += 64;
pctx->nBuildNumber = *(int *)src;
pctx->pRVAHeap = (const unsigned char *)(src + 20);
pctx->nFirstRVA = *(const long *)(src + 16);
pctx->pFuncNameHeap = (const char *)pctx->pRVAHeap - 4 + *(const long *)(src + 4);
pctx->pSegments = (unsigned long (*)[2])(pctx->pFuncNameHeap + *(const long *)(src + 8));
pctx->nSegments = *(const long *)(src + 12);
return true;
}
void VDDebugInfoDeinit( Context *pctx )
{
if( !pctx->sRawBlock.empty() )
pctx->sRawBlock = RString();
}
bool VDDebugInfoInitFromFile( Context *pctx )
{
if( pctx->Loaded() )
return true;
pctx->sRawBlock = RString();
pctx->pRVAHeap = NULL;
GetVDIPath( pctx->sFilename, ARRAYLEN(pctx->sFilename) );
pctx->sError = RString();
HANDLE h = CreateFile( pctx->sFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( h == INVALID_HANDLE_VALUE )
{
pctx->sError = werr_ssprintf( GetLastError(), "CreateFile failed" );
return false;
}
do {
DWORD dwFileSize = GetFileSize( h, NULL );
if( dwFileSize == INVALID_FILE_SIZE )
break;
char *pBuf = pctx->sRawBlock.GetBuffer( dwFileSize );
if( pBuf == NULL )
break;
DWORD dwActual;
int iRet = ReadFile(h, pBuf, dwFileSize, &dwActual, NULL);
CloseHandle(h);
pctx->sRawBlock.ReleaseBuffer( dwActual );
if( !iRet || dwActual != dwFileSize )
break;
if( VDDebugInfoInitFromMemory(pctx) )
return true;
} while(0);
VDDebugInfoDeinit(pctx);
return false;
}
static bool PointerIsInAnySegment( const Context *pctx, unsigned rva )
{
for( int i=0; i<pctx->nSegments; ++i )
{
if (rva >= pctx->pSegments[i][0] && rva < pctx->pSegments[i][0] + pctx->pSegments[i][1])
return true;
}
return false;
}
static const char *GetNameFromHeap(const char *heap, int idx)
{
while(idx--)
while(*heap++);
return heap;
}
long VDDebugInfoLookupRVA( const Context *pctx, unsigned rva, char *buf, int buflen )
{
if( !PointerIsInAnySegment(pctx, rva) )
return -1;
const unsigned char *pr = pctx->pRVAHeap;
const unsigned char *pr_limit = (const unsigned char *)pctx->pFuncNameHeap;
int idx = 0;
// Linearly unpack RVA deltas and find lower_bound
rva -= pctx->nFirstRVA;
if( (signed)rva < 0 )
return -1;
while( pr < pr_limit )
{
unsigned char c;
unsigned diff = 0;
do
{
c = *pr++;
diff = (diff << 7) | (c & 0x7f);
} while(c & 0x80);
rva -= diff;
if ((signed)rva < 0) {
rva += diff;
break;
}
++idx;
}
if( pr >= pr_limit )
return -1;
// Decompress name for RVA
const char *fn_name = GetNameFromHeap(pctx->pFuncNameHeap, idx);
if( !*fn_name )
fn_name = "(special)";
strncpy( buf, fn_name, buflen );
buf[buflen-1] = 0;
return rva;
}
}
bool ReadFromParent( int fd, void *p, int size )
{
char *buf = (char *) p;
int got = 0;
while( got < size )
{
int ret = read( fd, buf+got, size-got );
if( ret == -1 )
{
if( errno == EINTR )
continue;
fprintf( stderr, "Crash handler: error communicating with parent: %s\n", strerror(errno) );
return false;
}
if( ret == 0 )
{
fprintf( stderr, "Crash handler: EOF communicating with parent.\n" );
return false;
}
got += ret;
}
return true;
}
// General symbol lookup; uses VDDebugInfo for detailed information within the
// process, and DbgHelp for simpler information about loaded DLLs.
namespace SymbolLookup
{
HANDLE g_hParent;
bool InitDbghelp()
{
static bool bInitted = false;
if( !bInitted )
{
SymSetOptions( SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS );
if( !SymInitialize(g_hParent, NULL, TRUE) )
return false;
bInitted = true;
}
return true;
}
SYMBOL_INFO *GetSym( unsigned long ptr, DWORD64 &disp )
{
InitDbghelp();
static BYTE buffer[1024];
SYMBOL_INFO *pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO) + 1;
if( !SymFromAddr(g_hParent, ptr, &disp, pSymbol) )
return NULL;
return pSymbol;
}
const char *Demangle( const char *buf )
{
if( !InitDbghelp() )
return buf;
static char obuf[1024];
if( !UnDecorateSymbolName(buf, obuf, sizeof(obuf),
UNDNAME_COMPLETE
| UNDNAME_NO_CV_THISTYPE
| UNDNAME_NO_ALLOCATION_MODEL
| UNDNAME_NO_ACCESS_SPECIFIERS // no public:
| UNDNAME_NO_MS_KEYWORDS // no __cdecl
| UNDNAME_NO_MEMBER_TYPE // no virtual, static
) )
{
return buf;
}
if( obuf[0] == '_' )
{
strcat( obuf, "()" ); /* _main -> _main() */
return obuf+1; /* _main -> main */
}
return obuf;
}
RString CrashChildGetModuleBaseName( HMODULE hMod )
{
write( _fileno(stdout), &hMod, sizeof(hMod) );
int iFD = fileno(stdin);
int iSize;
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return "???";
RString sName;
char *pBuf = sName.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return "???";
sName.ReleaseBuffer( iSize );
return sName;
}
void SymLookup( VDDebugInfo::Context *pctx, const void *ptr, char *buf )
{
if( !pctx->Loaded() )
{
strcpy( buf, "error" );
return;
}
MEMORY_BASIC_INFORMATION meminfo;
VirtualQueryEx( g_hParent, ptr, &meminfo, sizeof meminfo );
char tmp[512];
long iAddress = VDDebugInfo::VDDebugInfoLookupRVA(pctx, (unsigned int)ptr, tmp, sizeof(tmp));
if( iAddress >= 0 )
{
wsprintf( buf, "%08x: %s [%08lx+%lx+%lx]", ptr, Demangle(tmp),
pctx->nFirstRVA,
((unsigned int) ptr) - pctx->nFirstRVA - iAddress,
iAddress );
return;
}
RString sName = CrashChildGetModuleBaseName( (HMODULE)meminfo.AllocationBase );
DWORD64 disp;
SYMBOL_INFO *pSymbol = GetSym( (unsigned int)ptr, disp );
if( pSymbol )
{
wsprintf( buf, "%08lx: %s!%s [%08lx+%lx+%lx]",
(unsigned long) ptr, sName.c_str(), pSymbol->Name,
(unsigned long) meminfo.AllocationBase,
(unsigned long) (pSymbol->Address) - (unsigned long) (meminfo.AllocationBase),
(unsigned long) disp);
return;
}
wsprintf( buf, "%08lx: %s!%08lx",
(unsigned long) ptr, sName.c_str(),
(unsigned long) meminfo.AllocationBase );
}
}
namespace
{
RString SpliceProgramPath( RString fn )
{
char szBuf[MAX_PATH];
GetModuleFileName( NULL, szBuf, sizeof(szBuf) );
char szModName[MAX_PATH];
char *pszFile;
GetFullPathName( szBuf, sizeof(szModName), szModName, &pszFile );
strcpy( pszFile, fn );
return szModName;
}
namespace
{
VDDebugInfo::Context g_debugInfo;
RString ReportCallStack( const void * const *Backtrace )
{
if( !g_debugInfo.Loaded() )
return ssprintf( "debug resource file '%s': %s.\n", g_debugInfo.sFilename, g_debugInfo.sError.c_str() );
if( g_debugInfo.nBuildNumber != int(version_num) )
{
return ssprintf( "Incorrect %s file (build %d, expected %d) for this version of " PRODUCT_FAMILY " -- call stack unavailable.\n",
g_debugInfo.sFilename, g_debugInfo.nBuildNumber, int(version_num) );
}
RString sRet;
for( int i = 0; Backtrace[i]; ++i )
{
char buf[10240];
SymbolLookup::SymLookup( &g_debugInfo, Backtrace[i], buf );
sRet += ssprintf( "%s\n", buf );
}
return sRet;
}
}
struct CompleteCrashData
{
CrashInfo m_CrashInfo;
RString m_sInfo;
RString m_sAdditionalLog;
RString m_sCrashedThread;
vector<RString> m_asRecent;
vector<RString> m_asCheckpoints;
};
static void MakeCrashReport( const CompleteCrashData &Data, RString &sOut )
{
sOut += ssprintf(
"%s crash report (build %d, %s)\n"
"--------------------------------------\n\n",
PRODUCT_ID_VER, version_num, version_time );
sOut += ssprintf( "Crash reason: %s\n", Data.m_CrashInfo.m_CrashReason );
sOut += ssprintf( "\n" );
// Dump thread stacks
static char buf[1024*32];
sOut += ssprintf( "%s\n", join("\n", Data.m_asCheckpoints).c_str() );
sOut += ReportCallStack( Data.m_CrashInfo.m_BacktracePointers );
sOut += ssprintf( "\n" );
if( Data.m_CrashInfo.m_AlternateThreadBacktrace[0] )
{
for( int i = 0; i < CrashInfo::MAX_BACKTRACE_THREADS; ++i )
{
if( !Data.m_CrashInfo.m_AlternateThreadBacktrace[i][0] )
continue;
sOut += ssprintf( "Thread %s:\n", Data.m_CrashInfo.m_AlternateThreadName[i] );
sOut += ssprintf( "\n" );
sOut += ReportCallStack( Data.m_CrashInfo.m_AlternateThreadBacktrace[i] );
sOut += ssprintf( "" );
}
}
sOut += ssprintf( "Static log:\n" );
sOut += ssprintf( "%s", Data.m_sInfo.c_str() );
sOut += ssprintf( "%s", Data.m_sAdditionalLog.c_str() );
sOut += ssprintf( "\n" );
sOut += ssprintf( "Partial log:\n" );
for( size_t i = 0; i < Data.m_asRecent.size(); ++i )
sOut += ssprintf( "%s\n", Data.m_asRecent[i].c_str() );
sOut += ssprintf( "\n" );
sOut += ssprintf( "-- End of report\n" );
}
static void DoSave( const RString &sReport )
{
RString sName = SpliceProgramPath( "../crashinfo.txt" );
SetFileAttributes( sName, FILE_ATTRIBUTE_NORMAL );
FILE *pFile = fopen( sName, "w+" );
if( pFile == NULL )
return;
fprintf( pFile, "%s", sReport.c_str() );
fclose( pFile );
/* Discourage changing crashinfo.txt. */
SetFileAttributes( sName, FILE_ATTRIBUTE_READONLY );
}
void ViewWithNotepad(const char *str)
{
char buf[256] = "";
strcat( buf, "notepad.exe " );
strcat( buf, str );
RString cwd = SpliceProgramPath( "" );
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
CreateProcess(
NULL, // pointer to name of executable module
buf, // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
false, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
cwd, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
}
bool ReadCrashDataFromParent( int iFD, CompleteCrashData &Data )
{
_setmode( _fileno(stdin), O_BINARY );
/* 0. Read the parent handle. */
if( !ReadFromParent(iFD, &SymbolLookup::g_hParent, sizeof(SymbolLookup::g_hParent)) )
return false;
/* 1. Read the CrashData. */
if( !ReadFromParent(iFD, &Data.m_CrashInfo, sizeof(Data.m_CrashInfo)) )
return false;
/* 2. Read info. */
int iSize;
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return false;
char *pBuf = Data.m_sInfo.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return false;
Data.m_sInfo.ReleaseBuffer( iSize );
/* 3. Read AdditionalLog. */
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return false;
pBuf = Data.m_sAdditionalLog.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return false;
Data.m_sAdditionalLog.ReleaseBuffer( iSize );
/* 4. Read RecentLogs. */
int iCnt = 0;
if( !ReadFromParent(iFD, &iCnt, sizeof(iCnt)) )
return false;
for( int i = 0; i < iCnt; ++i )
{
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return false;
RString sBuf;
pBuf = sBuf.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return false;
Data.m_asRecent.push_back( sBuf );
sBuf.ReleaseBuffer( iSize );
}
/* 5. Read CHECKPOINTs. */
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return false;
RString sBuf;
pBuf = sBuf.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return false;
split( sBuf, "$$", Data.m_asCheckpoints );
sBuf.ReleaseBuffer( iSize );
/* 6. Read the crashed thread's name. */
if( !ReadFromParent(iFD, &iSize, sizeof(iSize)) )
return false;
pBuf = Data.m_sCrashedThread.GetBuffer( iSize );
if( !ReadFromParent(iFD, pBuf, iSize) )
return false;
Data.m_sCrashedThread.ReleaseBuffer();
return true;
}
/*
* Localization for the crash handler is different, and a little tricky. We don't
* have ThemeManager loaded, so we have to localize it ourself. We can supply
* translations with our own substitution function. We need to figure out which
* language to use. Since these strings won't be pulled from the theme, defer
* loading them until we use them. XXX
*/
static LocalizedString A_CRASH_HAS_OCCURRED;
static LocalizedString REPORTING_THE_PROBLEM;
static LocalizedString CLOSE;
static LocalizedString CANCEL;
static LocalizedString VIEW_UPDATE;
static LocalizedString UPDATE_IS_AVAILABLE;
static LocalizedString UPDATE_IS_NOT_AVAILABLE;
static LocalizedString ERROR_SENDING_REPORT;
// #define AUTOMATED_CRASH_REPORTS
#define CRASH_REPORT_HOST "example.com"
#define CRASH_REPORT_PORT 80
#define CRASH_REPORT_PATH "/report.cgi"
void LoadLocalizedStrings()
{
#if defined(AUTOMATED_CRASH_REPORTS)
A_CRASH_HAS_OCCURRED.Load( "CrashHandler",
"A crash has occurred. Would you like to automatically report the "
"problem and check for updates?" );
#else
A_CRASH_HAS_OCCURRED.Load( "CrashHandler",
"A crash has occurred. Diagnostic information has been saved to a file "
"called \"crashinfo.txt\" in the game program directory." );
#endif
REPORTING_THE_PROBLEM.Load( "CrashHandler",
"Reporting the problem and checking for updates ..." );
CLOSE.Load( "CrashHandler", "&Close" );
CANCEL.Load( "CrashHandler", "&Cancel" );
VIEW_UPDATE.Load( "CrashHandler", "View &update" );
UPDATE_IS_AVAILABLE.Load( "CrashHandler", "An update is available." );
UPDATE_IS_NOT_AVAILABLE.Load( "CrashHandler", "The error has been reported. No updates are available." );
ERROR_SENDING_REPORT.Load( "CrashHandler", "An error was encountered sending the report." );
}
class CrashDialog: public WindowsDialogBox
{
public:
CrashDialog( const RString &sCrashReport, const CompleteCrashData &CrashData );
~CrashDialog();
protected:
virtual BOOL HandleMessage( UINT msg, WPARAM wParam, LPARAM lParam );
private:
void SetDialogInitial();
NetworkPostData *m_pPost;
RString m_sUpdateURL;
const RString m_sCrashReport;
CompleteCrashData m_CrashData;
};
CrashDialog::CrashDialog( const RString &sCrashReport, const CompleteCrashData &CrashData ):
m_sCrashReport( sCrashReport ),
m_CrashData( CrashData )
{
LoadLocalizedStrings();
m_pPost = NULL;
}
CrashDialog::~CrashDialog()
{
delete m_pPost;
}
void CrashDialog::SetDialogInitial()
{
HWND hDlg = GetHwnd();
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), A_CRASH_HAS_OCCURRED.GetValue() );
SetWindowText( GetDlgItem(hDlg, IDC_BUTTON_CLOSE), CLOSE.GetValue() );
ShowWindow( GetDlgItem(hDlg, IDC_PROGRESS), false );
ShowWindow( GetDlgItem(hDlg, IDC_BUTTON_AUTO_REPORT), true );
}
BOOL CrashDialog::HandleMessage( UINT msg, WPARAM wParam, LPARAM lParam )
{
HWND hDlg = GetHwnd();
switch(msg)
{
case WM_INITDIALOG:
SetDialogInitial();
DialogUtil::SetHeaderFont( hDlg, IDC_STATIC_HEADER_TEXT );
return TRUE;
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
HWND hwndStatic = (HWND)lParam;
HBRUSH hbr = NULL;
// TODO: Change any attributes of the DC here
switch( GetDlgCtrlID(hwndStatic) )
{
case IDC_STATIC_HEADER_TEXT:
case IDC_STATIC_ICON:
hbr = (HBRUSH)::GetStockObject(WHITE_BRUSH);
SetBkMode( hdc, OPAQUE );
SetBkColor( hdc, RGB(255,255,255) );
break;
}
// TODO: Return a different brush if the default is not desired
return (BOOL)hbr;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BUTTON_CLOSE:
if( m_pPost != NULL )
{
/* Cancel reporting, and revert the dialog as if "report" had not been pressed. */
m_pPost->Cancel();
KillTimer( hDlg, 0 );
SetDialogInitial();
SAFE_DELETE( m_pPost );
return TRUE;
}
/* Close the dialog. */
EndDialog(hDlg, FALSE);
return TRUE;
case IDOK:
// EndDialog(hDlg, TRUE); /* don't always exit on ENTER */
return TRUE;
case IDC_VIEW_LOG:
ViewWithNotepad("../log.txt");
break;
case IDC_CRASH_SAVE:
ViewWithNotepad("../crashinfo.txt");
return TRUE;
case IDC_BUTTON_RESTART:
Win32RestartProgram();
EndDialog( hDlg, FALSE );
break;
case IDC_BUTTON_REPORT:
GotoURL( REPORT_BUG_URL );
break;
case IDC_BUTTON_AUTO_REPORT:
if( !m_sUpdateURL.empty() )
{
/* We already sent the report, were told that there's an update, and
* substituted the URL. */
GotoURL( m_sUpdateURL );
break;
}
ShowWindow( GetDlgItem(hDlg, IDC_BUTTON_AUTO_REPORT), false );
ShowWindow( GetDlgItem(hDlg, IDC_PROGRESS), true );
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), REPORTING_THE_PROBLEM.GetValue() );
SetWindowText( GetDlgItem(hDlg, IDC_BUTTON_CLOSE), CANCEL.GetValue() );
SendDlgItemMessage( hDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0,100) );
SendDlgItemMessage( hDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0 );
/* Create the form data to send. */
m_pPost = new NetworkPostData;
m_pPost->SetData( "Product", PRODUCT_ID );
m_pPost->SetData( "Version", PRODUCT_VER );
m_pPost->SetData( "Arch", HOOKS->GetArchName().c_str() );
m_pPost->SetData( "Report", m_sCrashReport );
m_pPost->SetData( "Reason", m_CrashData.m_CrashInfo.m_CrashReason );
m_pPost->Start( CRASH_REPORT_HOST, CRASH_REPORT_PORT, CRASH_REPORT_PATH );
SetTimer( hDlg, 0, 100, NULL );
break;
}
break;
case WM_TIMER:
{
if( m_pPost == NULL )
break;
float fProgress = m_pPost->GetProgress();
SendDlgItemMessage( hDlg, IDC_PROGRESS, PBM_SETPOS, int(fProgress*100), 0 );
if( m_pPost->IsFinished() )
{
KillTimer( hDlg, 0 );
/* Grab the result, which is the data output from the HTTP request. It's
* simple XML. */
RString sResult = m_pPost->GetResult();
RString sError = m_pPost->GetError();
if( sError.empty() && sResult.empty() )
sError = "No data received";
SAFE_DELETE( m_pPost );
XNode xml;
if( sError.empty() )
{
RString sError;
XmlFileUtil::Load( &xml, sResult, sError );
if( !sError.empty() )
{
sError = ssprintf( "Error parsing response: %s", sError.c_str() );
xml.Clear();
}
}
int iID;
if( !sError.empty() )
{
/* On error, don't show the "report" button again. If the submission was actually
* successful, then it'd be too easy to accidentally spam the server by holding
* down the button. */
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), ERROR_SENDING_REPORT.GetValue() );
}
else if( xml.GetAttrValue("UpdateAvailable", m_sUpdateURL) )
{
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), UPDATE_IS_AVAILABLE.GetValue() );
SetWindowText( GetDlgItem(hDlg, IDC_BUTTON_AUTO_REPORT), VIEW_UPDATE.GetValue() );
ShowWindow( GetDlgItem(hDlg, IDC_BUTTON_AUTO_REPORT), true );
}
else if( xml.GetAttrValue("ReportId", iID) )
{
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), UPDATE_IS_NOT_AVAILABLE.GetValue() );
}
else
{
SetWindowText( GetDlgItem(hDlg, IDC_MAIN_TEXT), ERROR_SENDING_REPORT.GetValue() );
}
if( xml.GetAttrValue("ReportId", iID) )
{
char sBuf[1024];
GetWindowText( hDlg, sBuf, 1024 );
SetWindowText( hDlg, ssprintf("%s (#%i)", sBuf, iID) );
}
ShowWindow( GetDlgItem(hDlg, IDC_PROGRESS), false );
SetWindowText( GetDlgItem(hDlg, IDC_BUTTON_CLOSE), CLOSE.GetValue() );
}
}
}
return FALSE;
}
void ChildProcess()
{
/* Read the crash data from the crashed parent. */
CompleteCrashData Data;
ReadCrashDataFromParent( fileno(stdin), Data );
RString sCrashReport;
VDDebugInfo::VDDebugInfoInitFromFile( &g_debugInfo );
MakeCrashReport( Data, sCrashReport );
VDDebugInfo::VDDebugInfoDeinit( &g_debugInfo );
DoSave( sCrashReport );
/* Tell the crashing process that it can exit. Be sure to write crashinfo.txt first. */
fclose( stdout );
/* Now that we've done that, the process is gone. Don't use g_hParent. */
CloseHandle( SymbolLookup::g_hParent );
SymbolLookup::g_hParent = NULL;
CrashDialog cd( sCrashReport, Data );
#if defined(AUTOMATED_CRASH_REPORTS)
cd.Run( IDD_REPORT_CRASH );
#else
cd.Run( IDD_DISASM_CRASH );
#endif
}
}
void CrashHandler::CrashHandlerHandleArgs( int argc, char* argv[] )
{
if( argc == 2 && !strcmp(argv[1], CHILD_MAGIC_PARAMETER) )
{
ChildProcess();
exit(0);
}
}
/*
* (c) 2003-2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,52 @@
#ifndef CRASH_HANDLER_INTERNAL_H
#define CRASH_HANDLER_INTERNAL_H
#define BACKTRACE_MAX_SIZE 100
struct CrashInfo
{
char m_CrashReason[1024*8];
const void *m_BacktracePointers[BACKTRACE_MAX_SIZE];
enum { MAX_BACKTRACE_THREADS = 32 };
const void *m_AlternateThreadBacktrace[MAX_BACKTRACE_THREADS][BACKTRACE_MAX_SIZE];
char m_AlternateThreadName[MAX_BACKTRACE_THREADS][128];
CrashInfo()
{
m_CrashReason[0] = 0;
memset( m_AlternateThreadBacktrace, 0, sizeof(m_AlternateThreadBacktrace) );
memset( m_AlternateThreadName, 0, sizeof(m_AlternateThreadName) );
m_BacktracePointers[0] = NULL;
}
};
#define CHILD_MAGIC_PARAMETER "--private-do-crash-handler"
#endif
/*
* (c) 2003-2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,788 @@
#include "global.h"
#include "CrashHandlerNetworking.h"
#include "RageThreads.h"
#include "RageLog.h"
#include "RageThreads.h"
#include "RageTimer.h"
#include "RageUtil.h"
#include "Foreach.h"
#if defined(WINDOWS)
#include <windows.h>
#include <winsock2.h>
#pragma comment(lib, "wsock32.lib")
#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
* 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().
*
* 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.
*
* 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.
*/
class NetworkStream
{
public:
enum ConnectionType
{
CONN_TCP,
CONN_UDP,
};
NetworkStream() { }
virtual ~NetworkStream() { }
/*
* 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.
*/
virtual void Close() = 0;
/*
* 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.
*/
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.)
*/
virtual void Write( const void *pBuffer, size_t iSize ) = 0;
/*
* 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
* 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.
*/
virtual void Cancel() = 0;
enum State
{
/* The stream is closed, and is ready to be opened. */
STATE_IDLE,
/* 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
* the other end, or shutdown() being called). */
STATE_SHUTDOWN,
/* When in CANCELLED, all blocking calls fail immediately; this state must be
* cleared explicitly by calling Close(). */
STATE_CANCELLED,
STATE_ERROR
};
State GetState() const { return m_State; }
RString GetError() const { return m_sError; }
protected:
State m_State;
RString m_sError;
};
class NetworkStream_Win32: public NetworkStream
{
public:
NetworkStream_Win32();
~NetworkStream_Win32();
void Open( const RString &sHost, int iPort, ConnectionType ct = CONN_TCP );
void Shutdown();
void Close();
int Read( void *pBuffer, size_t iSize );
void Write( const void *pBuffer, size_t iSize );
void Cancel();
private:
int WaitForCompletionOrCancellation( int iEvent );
void SetError( const RString &sError );
static RString WinSockErrorToString( int iError );
SOCKET m_Socket;
HANDLE m_hResolve;
HWND m_hResolveHwnd;
/* This event is signalled on cancellation, to wake us up if we're blocking. */
HANDLE m_hCompletionEvent;
RString m_sHost;
int m_iPort;
RageMutex m_Mutex;
};
NetworkStream *CreateNetworkStream()
{
static bool bInitted = false;
if( !bInitted )
{
bInitted = true;
WSADATA WSAData;
WORD iVersionRequested = MAKEWORD(2,0);
if( WSAStartup(iVersionRequested, &WSAData) != 0 )
return NULL;
}
return new NetworkStream_Win32;
}
/* WinSock implementation of NetworkStream. */
NetworkStream_Win32::NetworkStream_Win32():
m_Mutex( "NetworkTCPSocket" )
{
m_iPort = -1;
m_State = STATE_IDLE;
m_Socket = NULL;
#if defined(WINDOWS)
m_hResolve = NULL;
m_hResolveHwnd = NULL;
m_hCompletionEvent = CreateEvent( NULL, true, false, NULL );
#endif
}
NetworkStream_Win32::~NetworkStream_Win32()
{
Close();
CloseHandle( m_hCompletionEvent );
}
/* Wait for the specified network event to occur, or cancellation, whichever
* happens first. On cancellation, return -1; on error, return the error
* code; on success, return 0. */
int NetworkStream_Win32::WaitForCompletionOrCancellation( int iEvent )
{
while(1)
{
int iRet = WaitForSingleObject( m_hCompletionEvent, INFINITE );
if( iRet != WAIT_OBJECT_0 )
continue;
m_Mutex.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? */
if( m_State == STATE_CANCELLED )
{
m_Mutex.Unlock();
return -1;
}
m_Mutex.Unlock();
/* 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
* 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
* want hasn't happened yet. */
if( (events.lNetworkEvents & (1<<FD_CLOSE_BIT)) )
return WSAECONNRESET;
}
}
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 == -1 )
return RString();
switch( iError )
{
case WSAEINTR: return "Interrupted function call.";
case WSAEACCES: return "Permission denied.";
case WSAEFAULT: return "Bad address.";
case WSAEINVAL: return "Invalid argument.";
case WSAEMFILE: return "Too many open files.";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
case WSAEINPROGRESS: return "Operation now in progress.";
case WSAEALREADY: return "Operation already in progress.";
case WSAENOTSOCK: return "Socket operation on nonsocket.";
case WSAEDESTADDRREQ: return "Destination address required.";
case WSAEMSGSIZE: return "Message too long.";
case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
case WSAENOPROTOOPT: return "Bad protocol option.";
case WSAEPROTONOSUPPORT: return "Protocol not supported.";
case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
case WSAEOPNOTSUPP: return "Operation not supported.";
case WSAEPFNOSUPPORT: return "Protocol family not supported.";
case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
case WSAEADDRINUSE: return "Address already in use.";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
case WSAENETDOWN: return "Network is down.";
case WSAENETUNREACH: return "Network is unreachable.";
case WSAENETRESET: return "Network dropped connection on reset.";
case WSAECONNABORTED: return "Software caused connection abort.";
case WSAECONNRESET: return "Connection reset by peer.";
case WSAENOBUFS: return "No buffer space available.";
case WSAEISCONN: return "Socket is already connected.";
case WSAENOTCONN: return "Socket is not connected.";
case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
case WSAETIMEDOUT: return "Connection timed out.";
case WSAECONNREFUSED: return "Connection refused.";
case WSAEHOSTDOWN: return "Host is down.";
case WSAEHOSTUNREACH: return "No route to host.";
case WSAEPROCLIM: return "Too many processes.";
case WSASYSNOTREADY: return "Network subsystem is unavailable.";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
case WSAEDISCON: return "Graceful shutdown in progress. ";
case WSATYPE_NOT_FOUND: return "Class type not found.";
case WSAHOST_NOT_FOUND: return "Host not found.";
case WSATRY_AGAIN: return "Nonauthoritative host not found.";
case WSANO_RECOVERY: return "This is a nonrecoverable error.";
case WSANO_DATA: return "Valid name, no data record of requested type.";
case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
case WSA_IO_PENDING: return "Overlapped operations will complete later.";
case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
case WSASYSCALLFAILURE: return "System call failure.";
default: return ssprintf( "unknown Winsock error %i", iError );
}
}
void NetworkStream_Win32::SetError( const RString &sError )
{
m_Mutex.Lock();
if( m_State != STATE_CANCELLED )
{
m_sError = sError;
m_State = STATE_ERROR;
}
if( m_Socket != INVALID_SOCKET )
{
closesocket( m_Socket );
m_Socket = INVALID_SOCKET;
}
m_Mutex.Unlock();
}
/* WSAAsyncGetHostByName returns events through a window. */
#include "MessageWindow.h"
class ResolveMessageWindow: public MessageWindow
{
public:
ResolveMessageWindow(): MessageWindow("DNS notification window")
{
m_iResult = 0;
}
int GetResult() const { return m_iResult; }
protected:
bool HandleMessage( UINT msg, WPARAM wParam, LPARAM lParam )
{
if( msg == WM_USER )
{
m_iResult = WSAGETASYNCERROR( lParam );
StopRunning();
return true;
}
if( msg == WM_USER+1 )
{
m_iResult = 0;
StopRunning();
return true;
}
return false;
}
int m_iResult;
};
void NetworkStream_Win32::Open( const RString &sHost, int iPort, ConnectionType ct )
{
m_Mutex.Lock();
if( m_State == STATE_CANCELLED )
{
m_Mutex.Unlock();
return;
}
/* 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. */
hostent *pHost = NULL;
char pBuf[MAXGETHOSTSTRUCT];
{
pHost = (hostent *) pBuf;
ResolveMessageWindow mw;
m_hResolve = WSAAsyncGetHostByName(
mw.GetHwnd(),
WM_USER,
m_sHost,
(char *) pHost,
MAXGETHOSTSTRUCT
);
m_hResolveHwnd = mw.GetHwnd();
m_Mutex.Unlock();
mw.Run();
m_Mutex.Lock();
m_hResolve = NULL;
m_hResolveHwnd = NULL;
if( m_State == STATE_CANCELLED )
{
m_Mutex.Unlock();
return;
}
int iError = mw.GetResult();
if( iError )
{
SetError( ssprintf("DNS error: %s", WinSockErrorToString(iError).c_str() ) );
m_Mutex.Unlock();
return;
}
m_Mutex.Unlock();
}
{
sockaddr_in addr;
addr.sin_addr.s_addr = *(DWORD *)pHost->h_addr_list[0];
addr.sin_family = PF_INET;
addr.sin_port = htons( (uint16_t) iPort );
m_Mutex.Lock();
m_Socket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
if( m_Socket == INVALID_SOCKET )
{
int iError = WSAGetLastError();
SetError( ssprintf("Error creating socket: %s", WinSockErrorToString(iError).c_str() ) );
return;
}
/* 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 );
/* Start opening the connection. */
int iResult = connect(m_Socket, (SOCKADDR *) &addr, sizeof(addr));
m_Mutex.Unlock();
/* We expect EINPROGRESS/WSAEWOULDBLOCK. */
if( iResult == SOCKET_ERROR )
{
/* Block until the connection attempt completes. */
int iError = WSAGetLastError();
if( iError == WSAEWOULDBLOCK )
iError = WaitForCompletionOrCancellation( FD_CONNECT_BIT );
if( iError )
{
SetError( ssprintf("Couldn't connect: %s", WinSockErrorToString(iError).c_str() ) );
return;
}
}
}
m_State = STATE_CONNECTED;
}
void NetworkStream_Win32::Close()
{
if( m_State == STATE_IDLE )
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()
* first. */
Shutdown();
m_Mutex.Lock();
if( m_State == STATE_CANCELLED )
return;
if( m_Socket != INVALID_SOCKET )
closesocket( m_Socket );
m_Socket = INVALID_SOCKET;
m_State = STATE_IDLE;
m_Mutex.Unlock();
}
void NetworkStream_Win32::Shutdown()
{
/* If we're not in a normal, stable state (eg. an error occurred, or we were
* cancelled), don't wait to flush. */
if( m_State != STATE_CONNECTED )
return;
shutdown( m_Socket, SD_BOTH );
m_State = STATE_SHUTDOWN;
}
void NetworkStream_Win32::Cancel()
{
m_Mutex.Lock();
/* Mark cancellation. */
m_State = STATE_CANCELLED;
/* 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
* 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(). */
SetEvent( m_hCompletionEvent );
m_Mutex.Unlock();
}
int NetworkStream_Win32::Read( void *pBuffer, size_t iSize )
{
if( m_State != STATE_CONNECTED )
return 0;
char *p = (char *) pBuffer;
int iRead = 0;
while( iSize > 0 )
{
int iRet = recv( m_Socket, p, iSize, 0 );
if( iRet > 0 )
{
p += iRet;
iSize -= iRet;
iRead += iRet;
continue;
}
if( iRet == 0 )
{
/* 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. */
if( iRead > 0 )
break;
iError = WaitForCompletionOrCancellation( FD_READ_BIT );
if( iError == 0 )
continue;
}
/* 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. */
SetError( ssprintf("Error reading: %s", WinSockErrorToString(iError).c_str() ) );
break;
}
return iRead;
}
void NetworkStream_Win32::Write( const void *pBuffer, size_t iSize )
{
if( m_State != STATE_CONNECTED )
return;
const char *p = (const char *) pBuffer;
while( iSize > 0 )
{
int iRet = send( m_Socket, p, iSize, 0 );
ASSERT( iRet != 0 );
if( iRet > 0 )
{
p += iRet;
iSize -= iRet;
continue;
}
int iError = WSAGetLastError();
if( iError == WSAEWOULDBLOCK )
{
iError = WaitForCompletionOrCancellation( FD_WRITE_BIT );
if( iError == 0 )
continue;
}
SetError( ssprintf("Error writing: %s", WinSockErrorToString(iError).c_str() ) );
return;
}
}
/*
* Send a set of data over HTTP, as a POST form.
*/
NetworkPostData::NetworkPostData():
m_Mutex( "NetworkPostData" )
{
m_pStream = CreateNetworkStream();
}
NetworkPostData::~NetworkPostData()
{
delete m_pStream;
}
/* 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. */
while(1)
{
sMimeBoundaryOut = ssprintf( "--%08i", rand() );
FOREACHM_CONST( RString, RString, mapNameToData, d )
if( d->second.find(sMimeBoundaryOut) != RString::npos )
continue;
break;
}
FOREACHM_CONST( RString, RString, mapNameToData, d )
{
sOut += "--" + sMimeBoundaryOut + "\r\n";
sOut += ssprintf( "Content-Disposition: form-data; name=\"%s\"\r\n", d->first.c_str() );
sOut += "\r\n";
sOut += d->second;
sOut += "\r\n";
}
if( sOut.size() )
sOut += "--" + sMimeBoundaryOut + "--\r\n";
}
void NetworkPostData::HttpThread()
{
RString sData, sMimeBoundary;
CreateMimeData( m_Data, sData, sMimeBoundary );
// Stick to HTTP/1.0, since the protocol is simpler.
RString sBuf = ssprintf(
"%s %s HTTP/1.0\r\n"
"Accept: */*\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\r\n"
"Host: %s\r\n"
"Cache-Control: no-cache\r\n",
sData.size()? "POST":"GET",
m_sPath.c_str(),
m_sHost.c_str() );
if( sData.size() )
{
// sBuf += "Content-Type: application/x-www-form-urlencoded\r\n"
sBuf += "Content-Type: multipart/form-data; boundary=" + sMimeBoundary + "\r\n";
sBuf += ssprintf( "Content-Length: %i\r\n", sData.size() );
}
sBuf += "\r\n";
if( sData.size() )
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. */
SetProgress( 0 );
/*
* Begin connecting.
*/
m_pStream->Open( m_sHost, m_iPort );
SetProgress( 0.25f );
/* Send the form. */
m_pStream->Write( sBuf.data(), sBuf.size() );
/* Read the result. */
RString sResult;
while( m_pStream->GetState() == NetworkStream::STATE_CONNECTED )
{
sBuf.clear();
void *p = sBuf.GetBuffer( 1024 );
int iGot = m_pStream->Read( p, 1024 );
if( iGot >= 0 )
sBuf.ReleaseBuffer( iGot );
if( iGot <= 0 )
break;
sResult += sBuf;
}
SetProgress( 1.0f );
/* Parse the results. */
int iStart = 0, iSize = -1;
map<RString,RString> mapHeaders;
while( 1 )
{
split( sResult, "\n", iStart, iSize, false );
if( iStart == (int) sResult.size() )
break;
RString sLine = sResult.substr( iStart, iSize );
StripCrnl( sLine );
if( sLine.empty() )
{
m_sResult = sResult.substr( iStart+iSize+1 );
break;
}
}
m_bFinished = true;
}
void NetworkPostData::Start( const RString &sHost, int iPort, const RString &sPath )
{
m_bFinished = false;
m_sHost = sHost;
m_iPort = iPort;
m_sPath = sPath;
m_sStatus.clear();
m_fProgress = 0;
m_Thread.SetName( "HTTP thread" );
m_Thread.Create( HttpThread_Start, this );
}
void NetworkPostData::Cancel()
{
m_pStream->Cancel();
m_Thread.Wait();
}
bool NetworkPostData::IsFinished()
{
if( !m_bFinished )
return false;
m_Thread.Wait();
m_bFinished = false;
return true;
}
RString NetworkPostData::GetStatus() const
{
LockMut( m_Mutex );
return m_sStatus;
}
float NetworkPostData::GetProgress() const
{
LockMut( m_Mutex );
return m_fProgress;
}
RString NetworkPostData::GetError() const
{
return m_pStream->GetError();
}
void NetworkPostData::SetProgress( float fProgress )
{
m_Mutex.Lock();
m_fProgress = fProgress;
m_Mutex.Unlock();
}
void NetworkPostData::SetData( const RString &sKey, const RString &sData )
{
m_Data[sKey] = sData;
}
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,83 @@
#ifndef CRASH_HANDLER_NETWORKING_H
#define CRASH_HANDLER_NETWORKING_H
#include "RageThreads.h"
#include <map>
class NetworkStream;
/*
* Send a set of data over HTTP, as a POST form.
*/
class NetworkPostData
{
public:
NetworkPostData();
~NetworkPostData();
void SetData( const RString &sKey, const RString &sData );
/* 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. */
void Cancel();
/* If the operation is unfinished, return false. Otherwise, close the thread and return true. */
bool IsFinished();
RString GetStatus() const;
float GetProgress() const;
RString GetError() const;
RString GetResult() const { return m_sResult; }
private:
static void CreateMimeData( const map<RString,RString> &mapNameToData, RString &sOut, RString &sMimeBoundaryOut );
void SetProgress( float fProgress );
RageThread m_Thread;
void HttpThread();
static int HttpThread_Start( void *p ) { ((NetworkPostData *) p)->HttpThread(); return 0; }
mutable RageMutex m_Mutex;
RString m_sStatus;
float m_fProgress;
/* When the thread exists, it owns the rest of the data, regardless of m_Mutex. */
map<RString, RString> m_Data;
bool m_bFinished;
RString m_sHost;
int m_iPort;
RString m_sPath;
RString m_sResult;
NetworkStream *m_pStream;
};
#endif
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+286
View File
@@ -0,0 +1,286 @@
#include "global.h"
#include "DebugInfoHunt.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "VideoDriverInfo.h"
#include "RegistryAccess.h"
#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() );
LOG->Info( " %s, %s [%s]", info.sVersion.c_str(), info.sDate.c_str(), info.sDeviceID.c_str() );
}
static void GetMemoryDebugInfo()
{
MEMORYSTATUS mem;
GlobalMemoryStatus(&mem);
LOG->Info("Memory: %imb total, %imb swap (%imb swap avail)",
mem.dwTotalPhys / 1048576,
mem.dwTotalPageFile / 1048576,
mem.dwAvailPageFile / 1048576);
}
static void GetDisplayDriverDebugInfo()
{
RString sPrimaryDeviceName = GetPrimaryVideoName();
if( sPrimaryDeviceName == "" )
LOG->Info( "Primary display driver could not be determined." );
bool LoggedSomething = false;
for( int i=0; true; i++ )
{
VideoDriverInfo info;
if( !GetVideoDriverInfo(i, info) )
break;
if( sPrimaryDeviceName == "" ) // failed to get primary display name (NT4)
{
LogVideoDriverInfo( info );
LoggedSomething = true;
}
else if( info.sDescription == sPrimaryDeviceName )
{
LogVideoDriverInfo( info );
LoggedSomething = true;
break;
}
}
if( !LoggedSomething )
{
LOG->Info( "Primary display driver: %s", sPrimaryDeviceName.c_str() );
LOG->Warn("Couldn't find primary display driver; logging all drivers");
for( int i=0; true; i++ )
{
VideoDriverInfo info;
if( !GetVideoDriverInfo(i, info) )
break;
LogVideoDriverInfo( info );
}
}
}
static RString wo_ssprintf( MMRESULT err, const char *fmt, ...)
{
char buf[MAXERRORLENGTH];
waveOutGetErrorText(err, buf, MAXERRORLENGTH);
va_list va;
va_start(va, fmt);
RString s = vssprintf( fmt, va );
va_end(va);
return s += ssprintf( "(%s)", buf );
}
static void GetDriveDebugInfo9x()
{
/*
* HKEY_LOCAL_MACHINE\Enum\ESDI
* *\ (disk id)
* *\ (eg. MF&CHILD0000&PCI&VEN_8086&DEV_7111&SUBSYS_197615AD&REV_01&BUS_00&DEV_07&FUNC_0100)
* DMACurrentlyUsed 0 or 1
* DeviceDesc "GENERIC IDE DISK TYPE01"
*/
vector<RString> Drives;
if( !RegistryAccess::GetRegSubKeys( "HKEY_LOCAL_MACHINE\\Enum\\ESDI", Drives ) )
return;
for( unsigned drive = 0; drive < Drives.size(); ++drive )
{
vector<RString> IDs;
if( !RegistryAccess::GetRegSubKeys( Drives[drive], IDs ) )
continue;
for( unsigned id = 0; id < IDs.size(); ++id )
{
RString DeviceDesc;
RegistryAccess::GetRegValue( IDs[id], "DeviceDesc", DeviceDesc );
TrimRight( DeviceDesc );
int DMACurrentlyUsed = -1;
RegistryAccess::GetRegValue( IDs[id], "DMACurrentlyUsed", DMACurrentlyUsed );
LOG->Info( "Drive: \"%s\" DMA: %s",
DeviceDesc.c_str(), DMACurrentlyUsed? "yes":"NO" );
}
}
}
static void GetDriveDebugInfoNT()
{
/*
* HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\
* Scsi Port *\
* DMAEnabled 0 or 1
* Driver "Ultra", "atapi", etc
* Scsi Bus *\
* Target Id *\
* Logical Unit Id *\
* Identifier "WDC WD1200JB-75CRA0"
* Type "DiskPeripheral"
*/
vector<RString> Ports;
if( !RegistryAccess::GetRegSubKeys( "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\Scsi", Ports ) )
return;
for( unsigned i = 0; i < Ports.size(); ++i )
{
int DMAEnabled = -1;
RegistryAccess::GetRegValue( Ports[i], "DMAEnabled", DMAEnabled );
RString Driver;
RegistryAccess::GetRegValue( Ports[i], "Driver", Driver );
vector<RString> Busses;
if( !RegistryAccess::GetRegSubKeys( Ports[i], Busses, "Scsi Bus .*" ) )
continue;
for( unsigned bus = 0; bus < Busses.size(); ++bus )
{
vector<RString> TargetIDs;
if( !RegistryAccess::GetRegSubKeys( Busses[bus], TargetIDs, "Target Id .*" ) )
continue;
for( unsigned tid = 0; tid < TargetIDs.size(); ++tid )
{
vector<RString> LUIDs;
if( !RegistryAccess::GetRegSubKeys( TargetIDs[tid], LUIDs, "Logical Unit Id .*" ) )
continue;
for( unsigned luid = 0; luid < LUIDs.size(); ++luid )
{
RString Identifier;
RegistryAccess::GetRegValue( LUIDs[luid], "Identifier", Identifier );
TrimRight( Identifier );
LOG->Info( "Drive: \"%s\" Driver: %s DMA: %s",
Identifier.c_str(), Driver.c_str(), DMAEnabled == 1? "yes":DMAEnabled == -1? "N/A":"NO" );
}
}
}
}
}
static void GetDriveDebugInfo()
{
OSVERSIONINFO ovi;
ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if( !GetVersionEx(&ovi) )
{
LOG->Info("GetVersionEx failed!");
return;
}
switch( ovi.dwPlatformId )
{
case VER_PLATFORM_WIN32_WINDOWS:
GetDriveDebugInfo9x(); break;
case VER_PLATFORM_WIN32_NT:
GetDriveDebugInfoNT(); break;
}
}
static void GetWindowsVersionDebugInfo()
{
/* Detect operating system. */
OSVERSIONINFO ovi;
ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&ovi))
{
LOG->Info("GetVersionEx failed!");
return;
}
RString Ver = ssprintf("Windows %i.%i (", ovi.dwMajorVersion, ovi.dwMinorVersion);
if(ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
if(ovi.dwMinorVersion == 0)
Ver += "Win95";
else if(ovi.dwMinorVersion == 10)
Ver += "Win98";
else if(ovi.dwMinorVersion == 90)
Ver += "WinME";
else
Ver += "unknown 9x-based";
}
else if(ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if(ovi.dwMajorVersion == 4 && ovi.dwMinorVersion == 0)
Ver += "WinNT 4.0";
else if(ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 0)
Ver += "Win2000";
else if(ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 1)
Ver += "WinXP";
else
Ver += "unknown NT-based";
} else Ver += "???";
Ver += ssprintf(") build %i [%s]", ovi.dwBuildNumber & 0xffff, ovi.szCSDVersion);
LOG->Info("%s", Ver.c_str());
}
static void GetSoundDriverDebugInfo()
{
int cnt = waveOutGetNumDevs();
for(int i = 0; i < cnt; ++i)
{
WAVEOUTCAPS caps;
MMRESULT ret = waveOutGetDevCaps(i, &caps, sizeof(caps));
if(ret != MMSYSERR_NOERROR)
{
LOG->Info(wo_ssprintf(ret, "waveOutGetDevCaps(%i) failed", i));
continue;
}
LOG->Info("Sound device %i: %s, %i.%i, MID %i, PID %i %s", i, caps.szPname,
HIBYTE(caps.vDriverVersion),
LOBYTE(caps.vDriverVersion),
caps.wMid, caps.wPid,
caps.dwSupport & WAVECAPS_SAMPLEACCURATE? "":"(INACCURATE)");
}
}
void SearchForDebugInfo()
{
GetWindowsVersionDebugInfo();
GetMemoryDebugInfo();
GetDisplayDriverDebugInfo();
GetDriveDebugInfo();
GetSoundDriverDebugInfo();
}
/*
* (c) 2003-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+32
View File
@@ -0,0 +1,32 @@
#ifndef DEBUG_INFO_HUNT_H
#define DEBUG_INFO_HUNT_H
/* We want debug information; Windows makes us hunt for it. */
void SearchForDebugInfo();
#endif
/*
* (c) 2003-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+109
View File
@@ -0,0 +1,109 @@
#include "global.h"
#include "DialogUtil.h"
#include "RageUtil.h"
#include "ThemeManager.h"
#include "archutils/Win32/ErrorStrings.h"
// Create*Font copied from MFC's CFont
// pLogFont->nHeight is interpreted as PointSize * 10
static HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont)
{
HDC hDC = ::GetDC(NULL);
// convert nPointSize to logical units based on pDC
LOGFONT logFont = *lpLogFont;
POINT pt;
pt.y = ::GetDeviceCaps(hDC, LOGPIXELSY) * logFont.lfHeight;
pt.y /= 720; // 72 points/inch, 10 decipoints/point
pt.x = 0;
::DPtoLP(hDC, &pt, 1);
POINT ptOrg = { 0, 0 };
::DPtoLP(hDC, &ptOrg, 1);
logFont.lfHeight = -abs(pt.y - ptOrg.y);
ReleaseDC(NULL, hDC);
return ::CreateFontIndirect(&logFont);
}
// nPointSize is actually scaled 10x
static HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName)
{
ASSERT(lpszFaceName);
LOGFONT logFont;
memset(&logFont, 0, sizeof(LOGFONT));
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfHeight = nPointSize;
lstrcpyn(logFont.lfFaceName, lpszFaceName, strlen(logFont.lfFaceName));
return ::CreatePointFontIndirect(&logFont);
}
void DialogUtil::SetHeaderFont( HWND hdlg, int nID )
{
ASSERT( hdlg );
HWND hControl = ::GetDlgItem( hdlg, nID );
ASSERT( hControl );
// TODO: Fix font leak
const int FONT_POINTS = 16;
HFONT hfont = CreatePointFont( FONT_POINTS*10, "Arial Black" );
::SendMessage( hControl, WM_SETFONT, (WPARAM)hfont, TRUE );
}
void DialogUtil::LocalizeDialogAndContents( HWND hdlg )
{
ASSERT( THEME );
const int LARGE_STRING = 256;
char szTemp[LARGE_STRING] = "";
RString sGroup;
{
::GetWindowText( hdlg, szTemp, ARRAYLEN(szTemp) );
RString s = szTemp;
sGroup = "Dialog-"+s;
s = THEME->GetString( sGroup, s );
::SetWindowText( hdlg, ConvertUTF8ToACP(s).c_str() );
}
for( HWND hwndChild = ::GetTopWindow(hdlg); hwndChild != NULL; hwndChild = ::GetNextWindow(hwndChild,GW_HWNDNEXT) )
{
::GetWindowText( hwndChild, szTemp, ARRAYLEN(szTemp) );
RString s = szTemp;
if( s.empty() )
continue;
s = THEME->GetString( sGroup, s );
::SetWindowText( hwndChild, ConvertUTF8ToACP(s).c_str() );
}
}
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+37
View File
@@ -0,0 +1,37 @@
#ifndef DialogUtil_H
#define DialogUtil_H
#include <windows.h>
namespace DialogUtil
{
void SetHeaderFont( HWND hdlg, int nID );
void LocalizeDialogAndContents( HWND hdlg );
};
#endif
/*
* (c) 2002-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+55
View File
@@ -0,0 +1,55 @@
#include "global.h"
#include "DirectXHelpers.h"
#include "RageUtil.h"
#ifdef _XBOX
# include <D3DX8Core.h>
#else
# include <windows.h>
# include <dxerr8.h>
# if defined(_MSC_VER)
# pragma comment(lib, "dxerr8.lib")
# endif
#endif
RString hr_ssprintf( int hr, const char *fmt, ... )
{
va_list va;
va_start(va, fmt);
RString s = vssprintf( fmt, va );
va_end(va);
#ifdef _XBOX
char szError[1024] = "";
D3DXGetErrorString( hr, szError, sizeof(szError) );
#else
const char *szError = DXGetErrorString8( hr );
#endif
return s + ssprintf( " (%s)", szError );
}
/*
* Copyright (c) 2001-2005 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+31
View File
@@ -0,0 +1,31 @@
#ifndef DIRECTX_HELPERS_H
#define DIRECTX_HELPERS_H
RString hr_ssprintf( int hr, const char *fmt, ... );
#endif
/*
* Copyright (c) 2001-2005 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+97
View File
@@ -0,0 +1,97 @@
#include "global.h"
#include "ErrorStrings.h"
#include "RageUtil.h"
#if !defined(XBOX)
#include <windows.h>
#endif
RString werr_ssprintf( int err, const char *fmt, ... )
{
char buf[1024] = "";
#ifndef _XBOX
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
0, err, 0, buf, sizeof(buf), NULL);
#endif
/* Why is FormatMessage returning text ending with \r\n? */
RString text = buf;
text.Replace( "\n", "" );
text.Replace( "\r", " " ); /* foo\r\nbar -> foo bar */
TrimRight( text ); /* "foo\r\n" -> "foo" */
va_list va;
va_start(va, fmt);
RString s = vssprintf( fmt, va );
va_end(va);
return s += ssprintf( " (%s)", text.c_str() );
}
RString ConvertWstringToCodepage( wstring s, int iCodePage )
{
if( s.empty() )
return RString();
int iBytes = WideCharToMultiByte( iCodePage, 0, s.data(), s.size(),
NULL, 0, NULL, FALSE );
ASSERT_M( iBytes > 0, werr_ssprintf( GetLastError(), "WideCharToMultiByte" ).c_str() );
RString ret;
WideCharToMultiByte( CP_ACP, 0, s.data(), s.size(),
ret.GetBuffer( iBytes ), iBytes, NULL, FALSE );
ret.ReleaseBuffer( iBytes );
return ret;
}
RString ConvertUTF8ToACP( const RString &s )
{
return ConvertWstringToCodepage( RStringToWstring(s), CP_ACP );
}
wstring ConvertCodepageToWString( RString s, int iCodePage )
{
if( s.empty() )
return wstring();
int iBytes = MultiByteToWideChar( iCodePage, 0, s.data(), s.size(), NULL, 0 );
ASSERT_M( iBytes > 0, werr_ssprintf( GetLastError(), "MultiByteToWideChar" ).c_str() );
wchar_t *pTemp = new wchar_t[iBytes];
MultiByteToWideChar( iCodePage, 0, s.data(), s.size(), pTemp, iBytes );
wstring sRet( pTemp, iBytes );
delete [] pTemp;
return sRet;
}
RString ConvertACPToUTF8( const RString &s )
{
return WStringToRString( ConvertCodepageToWString(s, CP_ACP) );
}
/*
* Copyright (c) 2001-2005 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+35
View File
@@ -0,0 +1,35 @@
#ifndef ERROR_STRINGS_H
#define ERROR_STRINGS_H
RString werr_ssprintf( int err, const char *fmt, ... );
RString ConvertWstringToCodepage( wstring s, int iCodePage );
RString ConvertUTF8ToACP( const RString &s );
wstring ConvertCodepageToWString( RString s, int iCodePage );
RString ConvertACPToUTF8( const RString &s );
#endif
/*
* Copyright (c) 2001-2005 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+196
View File
@@ -0,0 +1,196 @@
#include "global.h"
#include "GetFileInformation.h"
#include "RageUtil.h"
#include "archutils/Win32/ErrorStrings.h"
#include <sys/stat.h>
#include <windows.h>
#include <tlhelp32.h>
#if defined(_MSC_VER)
#pragma comment(lib, "version.lib")
#endif
bool GetFileVersion( RString sFile, RString &sOut )
{
do {
/* 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: */
if( !GetFileVersionInfo( const_cast<char *>(sFile.c_str()), NULL, iSize, VersionBuffer.GetBuffer() ) )
break;
WORD *iTrans;
UINT iTransCnt;
if( !VerQueryValue( (void *) VersionBuffer.c_str() , "\\VarFileInfo\\Translation",
(void **) &iTrans, &iTransCnt ) )
break;
if( iTransCnt == 0 )
break;
char *str;
UINT len;
RString sRes = ssprintf( "\\StringFileInfo\\%04x%04x\\FileVersion",
iTrans[0], iTrans[1] );
if( !VerQueryValue( (void *) VersionBuffer.c_str(), (char *) sRes.c_str(),
(void **) &str, &len ) || len < 1)
break;
sOut = RString( str, len-1 );
} while(0);
/* Get the size and date. */
struct stat st;
if( stat( sFile, &st ) != -1 )
{
struct tm t;
gmtime_r( &st.st_mtime, &t );
if( !sOut.empty() )
sOut += " ";
sOut += ssprintf( "[%ib, %02i-%02i-%04i]", st.st_size, t.tm_mon+1, t.tm_mday, t.tm_year+1900 );
}
return true;
}
RString FindSystemFile( RString sFile )
{
char szWindowsPath[MAX_PATH];
GetWindowsDirectory( szWindowsPath, MAX_PATH );
const char *szPaths[] =
{
"/system32/",
"/system32/drivers/",
"/system/",
"/system/drivers/",
"/",
NULL
};
for( int i = 0; szPaths[i]; ++i )
{
RString sPath = ssprintf( "%s%s%s", szWindowsPath, szPaths[i], sFile.c_str() );
struct stat buf;
if( !stat(sPath, &buf) )
return sPath;
}
return RString();
}
/* 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. */
do {
HANDLE hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, iProcessID );
if( hSnap == NULL )
{
sName = werr_ssprintf( GetLastError(), "OpenProcess" );
break;
}
MODULEENTRY32 me;
ZERO( me );
me.dwSize = sizeof(MODULEENTRY32);
bool bRet = !!Module32First( hSnap, &me );
CloseHandle( hSnap );
if( bRet )
{
sName = me.szExePath;
return true;
}
sName = werr_ssprintf( GetLastError(), "Module32First" );
} while(0);
/* This method only works in NT/2K/XP. */
do {
static HINSTANCE hPSApi = NULL;
typedef DWORD (WINAPI* pfnGetModuleFileNameEx)(HANDLE,HMODULE,LPSTR,DWORD);
static pfnGetModuleFileNameEx pGetModuleFileNameEx = NULL;
static bool bTried = false;
if( !bTried )
{
bTried = true;
hPSApi = LoadLibrary("psapi.dll");
if( hPSApi == NULL )
{
sName = werr_ssprintf( GetLastError(), "LoadLibrary" );
break;
}
else
{
pGetModuleFileNameEx = (pfnGetModuleFileNameEx) GetProcAddress( hPSApi, "GetModuleFileNameExA" );
if( pGetModuleFileNameEx == NULL )
{
sName = werr_ssprintf( GetLastError(), "GetProcAddress" );
break;
}
}
}
if( pGetModuleFileNameEx != NULL )
{
HANDLE hProc = OpenProcess( PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, NULL, iProcessID );
if( hProc == NULL )
{
sName = werr_ssprintf( GetLastError(), "OpenProcess" );
break;
}
char buf[1024];
int iRet = pGetModuleFileNameEx( hProc, NULL, buf, 1024 );
CloseHandle( hProc );
if( iRet )
{
buf[iRet] = 0;
sName = buf;
return true;
}
sName = werr_ssprintf( GetLastError(), "GetModuleFileNameEx" );
}
} while(0);
return false;
}
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+35
View File
@@ -0,0 +1,35 @@
/* Windows-specific file helpers. */
#ifndef GET_FILE_INFORMATION_H
#define GET_FILE_INFORMATION_H
bool GetFileVersion( RString fsFile, RString &sOut );
RString FindSystemFile( RString sFile );
bool GetProcessFileName( uint32_t iProcessID, RString &sName );
#endif
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+86
View File
@@ -0,0 +1,86 @@
#include "global.h"
#include "GotoURL.h"
#include <windows.h>
#include <shellapi.h>
/* This is called from the crash handler; don't use RegistryAccess, since it's
* not crash-conditions safe. */
static LONG GetRegKey( HKEY key, RString subkey, LPTSTR retdata )
{
HKEY hKey;
LONG iRet = RegOpenKeyEx( key, subkey, 0, KEY_QUERY_VALUE, &hKey );
if( iRet != ERROR_SUCCESS )
return iRet;
long iDataSize = MAX_PATH;
char data[MAX_PATH];
RegQueryValue( hKey, "emulation", data, &iDataSize );
strcpy( retdata, data );
RegCloseKey( hKey );
return ERROR_SUCCESS;
}
bool GotoURL( RString sUrl )
{
// First try ShellExecute()
int iRet = (int) ShellExecute( NULL, "open", sUrl, NULL, NULL, SW_SHOWDEFAULT );
// If it failed, get the .htm regkey and lookup the program
if( iRet > 32 )
return true;
char key[2*MAX_PATH];
if( GetRegKey(HKEY_CLASSES_ROOT, ".htm", key) != ERROR_SUCCESS )
return false;
strcpy( key, "\\shell\\open\\command" );
if( GetRegKey(HKEY_CLASSES_ROOT, key, key) != ERROR_SUCCESS )
return false;
char *szPos = strstr( key, "\"%1\"" );
if( szPos == NULL )
{
// No quotes found. Check for %1 without quotes
szPos = strstr( key, "%1" );
if( szPos == NULL )
szPos = key+lstrlen(key)-1; // No parameter.
else
*szPos = '\0'; // Remove the parameter
}
else
*szPos = '\0'; // Remove the parameter
strcat( szPos, " " );
strcat( szPos, sUrl );
return WinExec( key, SW_SHOWDEFAULT ) > 32;
}
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+33
View File
@@ -0,0 +1,33 @@
/* Open URLs in a browser. */
#ifndef GOTO_URL_H
#define GOTO_URL_H
bool GotoURL( RString sUrl );
#endif
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+545
View File
@@ -0,0 +1,545 @@
#include "global.h"
#include "GraphicsWindow.h"
#include "ProductInfo.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageDisplay.h"
#include "DisplayResolutions.h"
#include "arch/ArchHooks/ArchHooks.h"
#include "archutils/Win32/AppInstance.h"
#include "archutils/Win32/Crash.h"
#include "archutils/Win32/ErrorStrings.h"
#include "archutils/Win32/WindowIcon.h"
#include "archutils/Win32/GetFileInformation.h"
#include <set>
static const RString g_sClassName = PRODUCT_ID;
static HWND g_hWndMain;
static HDC g_HDC;
static VideoModeParams g_CurrentParams;
static bool g_bResolutionChanged = false;
static bool g_bHasFocus = true;
static HICON g_hIcon = NULL;
static bool m_bWideWindowClass;
static bool g_bD3D = false;
/* If we're fullscreen, this is the mode we set. */
static DEVMODE g_FullScreenDevMode;
static bool g_bRecreatingVideoMode = false;
static UINT g_iQueryCancelAutoPlayMessage = 0;
static RString GetNewWindow()
{
HWND h = GetForegroundWindow();
if( h == NULL )
return "(NULL)";
DWORD iProcessID;
GetWindowThreadProcessId( h, &iProcessID );
RString sName;
GetProcessFileName( iProcessID, sName );
sName = Basename(sName);
return sName;
}
static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );
/* Suppress autorun. */
if( msg == g_iQueryCancelAutoPlayMessage )
return true;
switch( msg )
{
case WM_ACTIVATE:
{
const bool bInactive = (LOWORD(wParam) == WA_INACTIVE);
const bool bMinimized = (HIWORD(wParam) != 0);
const bool bHadFocus = g_bHasFocus;
g_bHasFocus = !bInactive && !bMinimized;
LOG->Trace( "WM_ACTIVATE (%i, %i): %s", bInactive, bMinimized, g_bHasFocus? "has focus":"doesn't have focus" );
if( !g_bHasFocus )
{
RString sName = GetNewWindow();
static set<RString> sLostFocusTo;
sLostFocusTo.insert( sName );
RString sStr;
for( set<RString>::const_iterator it = sLostFocusTo.begin(); it != sLostFocusTo.end(); ++it )
sStr += (sStr.size()?", ":"") + *it;
LOG->MapLog( "LOST_FOCUS", "Lost focus to: %s", sStr.c_str() );
}
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,
* because that's where most other apps seem to do it. */
if( g_bHasFocus && !bHadFocus )
{
ChangeDisplaySettings( &g_FullScreenDevMode, CDS_FULLSCREEN );
ShowWindow( g_hWndMain, SW_SHOWNORMAL );
}
else if( !g_bHasFocus && bHadFocus )
{
ChangeDisplaySettings( NULL, 0 );
}
}
return 0;
}
case WM_KILLFOCUS:
if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode )
ShowWindow( g_hWndMain, SW_SHOWMINNOACTIVE );
break;
/* Is there any reason we should care what size the user resizes the window to? */
// case WM_GETMINMAXINFO:
case WM_SETCURSOR:
if( !g_CurrentParams.windowed )
{
SetCursor( NULL );
return 1;
}
break;
case WM_SYSCOMMAND:
switch( wParam&0xFFF0 )
{
case SC_MONITORPOWER:
case SC_SCREENSAVE:
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
}
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
/* We handle all input ourself, via DirectInput. */
return 0;
case WM_CLOSE:
LOG->Trace("WM_CLOSE: shutting down");
ArchHooks::SetUserQuit();
return 0;
case WM_WINDOWPOSCHANGED:
{
/* 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;
RECT rect;
GetClientRect( hWnd, &rect );
int iWidth = rect.right - rect.left;
int iHeight = rect.bottom - rect.top;
if( g_CurrentParams.width != iWidth || g_CurrentParams.height != iHeight )
{
g_CurrentParams.width = iWidth;
g_CurrentParams.height = iHeight;
g_bResolutionChanged = true;
}
break;
}
}
CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );
if( m_bWideWindowClass )
return DefWindowProcW( hWnd, msg, wParam, lParam );
else
return DefWindowProcA( hWnd, msg, wParam, lParam );
}
static void AdjustVideoModeParams( VideoModeParams &p )
{
DEVMODE dm;
ZERO( dm );
dm.dmSize = sizeof(dm);
if( !EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) )
{
p.rate = 60;
LOG->Warn( "%s", werr_ssprintf(GetLastError(), "EnumDisplaySettings failed").c_str() );
return;
}
/*
* On a nForce 2 IGP on Windows 98, dm.dmDisplayFrequency sometimes
* (but not always) is 0.
*
* MSDN: When you call the EnumDisplaySettings function, the
* dmDisplayFrequency member may return with the value 0 or 1.
* 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.
*/
if( !(dm.dmFields & DM_DISPLAYFREQUENCY) ||
dm.dmDisplayFrequency == 0 ||
dm.dmDisplayFrequency == 1 )
{
p.rate = 60;
LOG->Warn( "EnumDisplaySettings doesn't know what the refresh rate is. %d %d %d", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel );
}
else
{
p.rate = dm.dmDisplayFrequency;
}
}
/* Set the display mode to the given size, bit depth and refresh. The refresh
* setting may be ignored. */
RString GraphicsWindow::SetScreenMode( const VideoModeParams &p )
{
if( p.windowed )
{
/* We're going windowed. If we were previously fullscreen, reset. */
ChangeDisplaySettings( NULL, 0 );
return RString();
}
DEVMODE DevMode;
ZERO( DevMode );
DevMode.dmSize = sizeof(DEVMODE);
DevMode.dmPelsWidth = p.width;
DevMode.dmPelsHeight = p.height;
DevMode.dmBitsPerPel = p.bpp;
DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
if( p.rate != REFRESH_DEFAULT )
{
DevMode.dmDisplayFrequency = p.rate;
DevMode.dmFields |= DM_DISPLAYFREQUENCY;
}
ChangeDisplaySettings( NULL, 0 );
int ret = ChangeDisplaySettings( &DevMode, CDS_FULLSCREEN );
if( ret != DISP_CHANGE_SUCCESSFUL && (DevMode.dmFields & DM_DISPLAYFREQUENCY) )
{
DevMode.dmFields &= ~DM_DISPLAYFREQUENCY;
ret = ChangeDisplaySettings( &DevMode, CDS_FULLSCREEN );
}
/* XXX: append error */
if( ret != DISP_CHANGE_SUCCESSFUL )
return "Couldn't set screen mode";
g_FullScreenDevMode = DevMode;
return RString();
}
static int GetWindowStyle( bool bWindowed )
{
if( bWindowed )
return WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
else
return WS_POPUP;
}
/* Set the final window size, set the window text and icon, and then unhide the
* window. */
void GraphicsWindow::CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow )
{
g_CurrentParams = p;
// Adjust g_CurrentParams to reflect the actual display settings.
AdjustVideoModeParams( g_CurrentParams );
if( g_hWndMain == NULL || bForceRecreateWindow )
{
int iWindowStyle = GetWindowStyle( p.windowed );
AppInstance inst;
HWND hWnd = CreateWindow( g_sClassName, "app", iWindowStyle,
0, 0, 0, 0, NULL, NULL, inst, NULL );
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( g_hWndMain != NULL )
{
/* While we change to the new window, don't do ChangeDisplaySettings in WM_ACTIVATE. */
g_bRecreatingVideoMode = true;
SetForegroundWindow( hWnd );
g_bRecreatingVideoMode = false;
GraphicsWindow::DestroyGraphicsWindow();
}
g_hWndMain = hWnd;
CrashHandler::SetForegroundWindow( g_hWndMain );
g_HDC = GetDC( g_hWndMain );
}
/* Update the window title. */
do
{
if( m_bWideWindowClass )
{
if( SetWindowText( g_hWndMain, ConvertUTF8ToACP(p.sWindowTitle).c_str() ) )
break;
}
SetWindowTextA( g_hWndMain, ConvertUTF8ToACP(p.sWindowTitle) );
} while(0);
/* Update the window icon. */
if( g_hIcon != NULL )
{
SetClassLong( g_hWndMain, GCL_HICON, (LONG) LoadIcon(NULL,IDI_APPLICATION) );
DestroyIcon( g_hIcon );
g_hIcon = NULL;
}
g_hIcon = IconFromFile( p.sIconFile );
if( g_hIcon != NULL )
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. */
int iWindowStyle = GetWindowStyle( p.windowed );
if( GetWindowLong( g_hWndMain, GWL_STYLE ) & WS_VISIBLE )
iWindowStyle |= WS_VISIBLE;
SetWindowLong( g_hWndMain, GWL_STYLE, iWindowStyle );
RECT WindowRect;
SetRect( &WindowRect, 0, 0, p.width, p.height );
AdjustWindowRect( &WindowRect, iWindowStyle, FALSE );
//LOG->Warn( "w = %d, h = %d", p.width, p.height );
const int iWidth = WindowRect.right - WindowRect.left;
const int iHeight = WindowRect.bottom - WindowRect.top;
/* If windowed, center the window. */
int x = 0, y = 0;
if( p.windowed )
{
x = GetSystemMetrics(SM_CXSCREEN)/2-iWidth/2;
y = GetSystemMetrics(SM_CYSCREEN)/2-iHeight/2;
}
/* 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() );
SetForegroundWindow( g_hWndMain );
/* Pump messages quickly, to make sure the window is completely set up.
* If we don't do this, then starting up in a D3D fullscreen window may
* cause all other windows on the system to be resized. */
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
GetMessage( &msg, NULL, 0, 0 );
DispatchMessage( &msg );
}
}
/* Shut down the window, but don't reset the video mode. */
void GraphicsWindow::DestroyGraphicsWindow()
{
if( g_HDC != NULL )
{
ReleaseDC( g_hWndMain, g_HDC );
g_HDC = NULL;
}
CHECKPOINT;
if( g_hWndMain != NULL )
{
DestroyWindow( g_hWndMain );
g_hWndMain = NULL;
CrashHandler::SetForegroundWindow( g_hWndMain );
}
CHECKPOINT;
if( g_hIcon != NULL )
{
DestroyIcon( g_hIcon );
g_hIcon = NULL;
}
CHECKPOINT;
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
CHECKPOINT;
GetMessage( &msg, NULL, 0, 0 );
CHECKPOINT;
DispatchMessage( &msg );
}
CHECKPOINT;
}
void GraphicsWindow::Initialize( bool bD3D )
{
/* A few things need to be handled differently for D3D. */
g_bD3D = bD3D;
AppInstance inst;
do
{
const wstring wsClassName = RStringToWstring( g_sClassName );
WNDCLASSW WindowClassW =
{
CS_OWNDC | CS_BYTEALIGNCLIENT,
GraphicsWindow_WndProc,
0, /* cbClsExtra */
0, /* cbWndExtra */
inst, /* hInstance */
NULL, /* set icon later */
LoadCursor( NULL, IDC_ARROW ), /* default cursor */
NULL, /* hbrBackground */
NULL, /* lpszMenuName */
wsClassName.c_str() /* lpszClassName */
};
m_bWideWindowClass = true;
if( RegisterClassW( &WindowClassW ) )
break;
WNDCLASS WindowClassA =
{
CS_OWNDC | CS_BYTEALIGNCLIENT,
GraphicsWindow_WndProc,
0, /* cbClsExtra */
0, /* cbWndExtra */
inst, /* hInstance */
NULL, /* set icon later */
LoadCursor( NULL, IDC_ARROW ), /* default cursor */
NULL, /* hbrBackground */
NULL, /* lpszMenuName */
g_sClassName /* lpszClassName */
};
m_bWideWindowClass = false;
if( !RegisterClassA( &WindowClassA ) )
RageException::Throw( "%s", werr_ssprintf( GetLastError(), "RegisterClass" ).c_str() );
} while(0);
g_iQueryCancelAutoPlayMessage = RegisterWindowMessage( "QueryCancelAutoPlay" );
}
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.
*/
ChangeDisplaySettings( NULL, 0 );
AppInstance inst;
UnregisterClass( g_sClassName, inst );
}
HDC GraphicsWindow::GetHDC()
{
ASSERT( g_HDC != NULL );
return g_HDC;
}
const VideoModeParams &GraphicsWindow::GetParams()
{
return g_CurrentParams;
}
void GraphicsWindow::Update()
{
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
GetMessage( &msg, NULL, 0, 0 );
DispatchMessage( &msg );
}
HOOKS->SetHasFocus( g_bHasFocus );
if( g_bResolutionChanged && DISPLAY != NULL )
{
//LOG->Warn( "Changing resolution" );
/* 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();
}
}
HWND GraphicsWindow::GetHwnd()
{
return g_hWndMain;
}
void GraphicsWindow::GetDisplayResolutions( DisplayResolutions &out )
{
DEVMODE dm;
ZERO( dm );
dm.dmSize = sizeof(dm);
int i=0;
while(EnumDisplaySettings(NULL, i++, &dm))
{
if(ChangeDisplaySettings(&dm, CDS_TEST)==DISP_CHANGE_SUCCESSFUL)
{
DisplayResolution res = { dm.dmPelsWidth, dm.dmPelsHeight };
out.insert( res );
}
}
}
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+61
View File
@@ -0,0 +1,61 @@
/* GraphicsWindow - Sets up a window for OpenGL/D3D. */
#ifndef GRAPHICS_WINDOW_H
#define GRAPHICS_WINDOW_H
#include <windows.h>
#include "DisplayResolutions.h"
class VideoModeParams;
class DisplayResolution;
namespace GraphicsWindow
{
/* Set up, and create a hidden window. This only needs to be called once. */
void Initialize( bool bD3D );
/* Shut down completely. */
void Shutdown();
/* 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). */
void CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow = false );
void DestroyGraphicsWindow();
void GetDisplayResolutions( DisplayResolutions &out );
const VideoModeParams &GetParams();
HDC GetHDC();
void Update();
HWND GetHwnd();
};
#endif
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+92
View File
@@ -0,0 +1,92 @@
#include "global.h"
#include "MessageWindow.h"
#include "RageUtil.h"
#include "AppInstance.h"
#include "archutils/Win32/ErrorStrings.h"
MessageWindow::MessageWindow( const RString &sClassName )
{
AppInstance inst;
WNDCLASS WindowClass =
{
CS_OWNDC | CS_BYTEALIGNCLIENT,
WndProc,
0, /* cbClsExtra */
0, /* cbWndExtra */
inst, /* hInstance */
NULL, /* set icon later */
LoadCursor( NULL, IDC_ARROW ), /* default cursor */
NULL, /* hbrBackground */
NULL, /* lpszMenuName */
sClassName /* lpszClassName */
};
if( !RegisterClassA(&WindowClass) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS )
RageException::Throw( "%s", werr_ssprintf( GetLastError(), "RegisterClass" ).c_str() );
// XXX: on 2k/XP, use HWND_MESSAGE as parent
m_hWnd = CreateWindow( sClassName, sClassName, WS_DISABLED, 0, 0, 0, 0, NULL, NULL, inst, NULL );
ASSERT( m_hWnd != NULL );
SetProp( m_hWnd, "MessageWindow", this );
}
MessageWindow::~MessageWindow()
{
RemoveProp( m_hWnd, "MessageWindow" );
DestroyWindow( m_hWnd );
}
void MessageWindow::Run()
{
/* Process messages until StopRunning is called. */
m_bDone = false;
while( !m_bDone )
{
MSG msg;
int iRet = GetMessage( &msg, m_hWnd, 0, 0 );
ASSERT( iRet != -1 );
if( iRet == 0 )
break;
DispatchMessage( &msg );
}
}
void MessageWindow::StopRunning()
{
m_bDone = true;
}
LRESULT CALLBACK MessageWindow::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
MessageWindow *pThis = (MessageWindow *) GetProp( hWnd, "MessageWindow" );
if( pThis != NULL && pThis->HandleMessage(msg, wParam, lParam) )
return 0;
return DefWindowProc( hWnd, msg, wParam, lParam );
}
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+54
View File
@@ -0,0 +1,54 @@
/* MessageWindow - simplifies creation of windows that exist only to receive messages. */
#ifndef MESSAGE_WINDOW_H
#define MESSAGE_WINDOW_H
#include <windows.h>
class MessageWindow
{
public:
MessageWindow( const RString &sClassName );
~MessageWindow();
/* Run the message loop until WM_QUIT is received. */
void Run();
HWND GetHwnd() { return m_hWnd; }
protected:
virtual bool HandleMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { return false; }
void StopRunning();
private:
static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
HWND m_hWnd;
bool m_bDone;
};
#endif
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+243
View File
@@ -0,0 +1,243 @@
#include "global.h"
#include "RegistryAccess.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "archutils/Win32/ErrorStrings.h"
#include <windows.h>
/* Given "HKEY_LOCAL_MACHINE\hardware\foo", return "hardware\foo", and place
* the HKEY_LOCAL_MACHINE constant in key. */
static bool GetRegKeyType( const RString &sIn, RString &sOut, HKEY &key )
{
size_t iBackslash = sIn.find( '\\' );
if( iBackslash == sIn.npos )
{
LOG->Warn( "Invalid registry key: \"%s\" ", sIn.c_str() );
return false;
}
RString sType = sIn.substr( 0, iBackslash );
if( !sType.CompareNoCase( "HKEY_CLASSES_ROOT" ) ) key = HKEY_CLASSES_ROOT;
else if( !sType.CompareNoCase( "HKEY_CURRENT_CONFIG" ) ) key = HKEY_CURRENT_CONFIG;
else if( !sType.CompareNoCase( "HKEY_CURRENT_USER" ) ) key = HKEY_CURRENT_USER;
else if( !sType.CompareNoCase( "HKEY_LOCAL_MACHINE" ) ) key = HKEY_LOCAL_MACHINE;
else if( !sType.CompareNoCase( "HKEY_USERS" ) ) key = HKEY_USERS;
else
{
LOG->Warn( "Invalid registry key: \"%s\" ", sIn.c_str() );
return false;
}
sOut = sIn.substr( iBackslash+1 );
return true;
}
/* Given a full key, eg. "HKEY_LOCAL_MACHINE\hardware\foo", open it and return it.
* On error, return NULL. */
enum RegKeyMode { READ, WRITE };
static HKEY OpenRegKey( const RString &sKey, RegKeyMode mode, bool bWarnOnError = true )
{
RString sSubkey;
HKEY hType;
if( !GetRegKeyType(sKey, sSubkey, hType) )
return NULL;
HKEY hRetKey;
LONG retval = RegOpenKeyEx( hType, sSubkey, 0, (mode==READ) ? KEY_READ:KEY_WRITE, &hRetKey );
if ( retval != ERROR_SUCCESS )
{
if( bWarnOnError )
LOG->Warn( werr_ssprintf(retval, "RegOpenKeyEx(%x,%s) error", hType, sSubkey.c_str()) );
return NULL;
}
return hRetKey;
}
bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, RString &sVal )
{
HKEY hKey = OpenRegKey( sKey, READ );
if( hKey == NULL )
return false;
char sBuffer[MAX_PATH];
DWORD iSize = sizeof(sBuffer);
DWORD iType;
LONG iRet = RegQueryValueEx( hKey, sName, NULL, &iType, (LPBYTE)sBuffer, &iSize );
RegCloseKey( hKey );
if( iRet != ERROR_SUCCESS )
return false;
/* Actually, CStrings are 8-bit clean, so we can accept any type of data. Remove
* this if that becomes useful. */
if( iType != REG_SZ && iType != REG_MULTI_SZ && iType != REG_EXPAND_SZ && iType != REG_BINARY )
return false; /* type mismatch */
if( iSize && (iType == REG_SZ || iType == REG_MULTI_SZ || iType == REG_EXPAND_SZ) )
--iSize; /* remove nul terminator */
sVal = RString( sBuffer, iSize );
return true;
}
bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, int &iVal, bool bWarnOnError )
{
HKEY hKey = OpenRegKey( sKey, READ, bWarnOnError );
if( hKey == NULL )
return false;
DWORD iValue;
DWORD iSize = sizeof(iValue);
DWORD iType;
LONG iRet = RegQueryValueEx( hKey, sName, NULL, &iType, (LPBYTE) &iValue, &iSize );
RegCloseKey( hKey );
if( iRet != ERROR_SUCCESS )
return false;
if( iType != REG_DWORD )
return false; /* type mismatch */
iVal = iValue;
return true;
}
bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, bool &bVal )
{
int iVal;
bool b = GetRegValue( sKey, sName, iVal );
bVal = !!iVal;
return b;
}
bool RegistryAccess::GetRegSubKeys( const RString &sKey, vector<RString> &lst, const RString &regex, bool bReturnPathToo )
{
HKEY hKey = OpenRegKey( sKey, READ );
if( hKey == NULL )
return false;
Regex re(regex);
bool bError = false;
for( int index = 0; ; ++index )
{
FILETIME ft;
char szBuffer[MAX_PATH];
DWORD iSize = sizeof(szBuffer);
LONG iRet = RegEnumKeyEx( hKey, index, szBuffer, &iSize, NULL, NULL, NULL, &ft);
if( iRet == ERROR_NO_MORE_ITEMS )
break;
if( iRet != ERROR_SUCCESS )
{
LOG->Warn( werr_ssprintf(iRet, "GetRegSubKeys(%p,%i) error", hKey, index) );
bError = true;
break;
}
RString sStr( szBuffer, iSize );
if( re.Compare(sStr) )
{
if( bReturnPathToo )
sStr = sKey + "\\" + sStr;
lst.push_back( sStr );
}
}
RegCloseKey( hKey );
return !bError;
}
bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, const RString &sVal )
{
HKEY hKey = OpenRegKey( sKey, WRITE );
if( hKey == NULL )
return false;
bool bSuccess = true;
TCHAR sz[255];
if( sVal.size() > 254 )
return false;
strcpy( sz, sVal.c_str() );
LONG lResult = ::RegSetValueEx(hKey, LPCTSTR(sName), 0, REG_SZ, (LPBYTE)sz, strlen(sz) + 1);
if( lResult != ERROR_SUCCESS )
bSuccess = false;
::RegCloseKey(hKey);
return bSuccess;
}
bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, bool bVal )
{
HKEY hKey = OpenRegKey( sKey, WRITE );
if( hKey == NULL )
return false;
bool bSuccess = true;
if (::RegSetValueEx(hKey, LPCTSTR(sName), 0,
REG_BINARY, (LPBYTE)&bVal, sizeof(bVal))
!= ERROR_SUCCESS)
bSuccess = false;
::RegCloseKey(hKey);
return bSuccess;
}
bool RegistryAccess::CreateKey( const RString &sKey )
{
RString sSubkey;
HKEY hType;
if( !GetRegKeyType(sKey, sSubkey, hType) )
return NULL;
HKEY hKey;
DWORD dwDisposition = 0;
if( ::RegCreateKeyEx(
hType,
sSubkey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDisposition ) != ERROR_SUCCESS )
{
return false;
}
::RegCloseKey(hKey);
return true;
}
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+46
View File
@@ -0,0 +1,46 @@
/* RegistryAccess - Windows registry helpers */
#ifndef REGISTRY_ACCESS_H
#define REGISTRY_ACCESS_H
namespace RegistryAccess
{
bool GetRegValue( const RString &sKey, const RString &sName, RString &val );
bool GetRegValue( const RString &sKey, const RString &sName, int &val, bool bWarnOnError = true );
bool GetRegValue( const RString &sKey, const RString &sName, bool &val );
bool GetRegSubKeys( const RString &sKey, vector<RString> &asList, const RString &sRegex = ".*", bool bReturnPathToo = true );
bool SetRegValue( const RString &sKey, const RString &sName, const RString &val );
bool SetRegValue( const RString &sKey, const RString &sName, int val );
bool SetRegValue( const RString &sKey, const RString &sName, bool val );
bool CreateKey( const RString &sKey );
}
#endif
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+55
View File
@@ -0,0 +1,55 @@
#include "global.h"
#include "RestartProgram.h"
#include <windows.h>
void Win32RestartProgram()
{
TCHAR szFullAppPath[MAX_PATH];
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
// Relaunch
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
CreateProcess(
NULL, // pointer to name of executable module
szFullAppPath, // pointer to command line string
NULL, // process security attributes
NULL, // thread security attributes
false, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
ExitProcess( 0 );
/* not reached */
}
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+31
View File
@@ -0,0 +1,31 @@
#ifndef RESTART_PROGRAM_H
#define RESTART_PROGRAM_H
void Win32RestartProgram();
#endif
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+50
View File
@@ -0,0 +1,50 @@
#include "global.h"
#include "SpecialDirs.h"
#include <shlobj.h>
static RString GetSpecialFolderPath( int csidl )
{
RString sDir;
TCHAR szDir[MAX_PATH] = "";
BOOL bResult = SHGetSpecialFolderPath( NULL, szDir, csidl, FALSE );
ASSERT( bResult );
sDir = szDir;
sDir += "/";
return sDir;
}
RString SpecialDirs::GetAppDataDir()
{
return GetSpecialFolderPath( CSIDL_APPDATA );
}
RString SpecialDirs::GetDesktopDir()
{
return GetSpecialFolderPath( CSIDL_DESKTOP );
}
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+35
View File
@@ -0,0 +1,35 @@
#ifndef SpecialDirs_H
#define SpecialDirs_H
namespace SpecialDirs
{
RString GetAppDataDir();
RString GetDesktopDir();
};
#endif
/*
* (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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

+246
View File
@@ -0,0 +1,246 @@
#include "global.h"
#include "USB.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "archutils/Win32/ErrorStrings.h"
#if defined(_MSC_VER)
#pragma comment(lib, "archutils/Win32/ddk/setupapi.lib")
#pragma comment(lib, "archutils/Win32/ddk/hid.lib")
#endif
extern "C" {
#include "archutils/Win32/ddk/setupapi.h"
/* Quiet header warning: */
#include "archutils/Win32/ddk/hidsdi.h"
}
static RString GetUSBDevicePath( int iNum )
{
GUID guid;
HidD_GetHidGuid( &guid );
HDEVINFO DeviceInfo = SetupDiGetClassDevs( &guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) );
SP_DEVICE_INTERFACE_DATA DeviceInterface;
DeviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if( !SetupDiEnumDeviceInterfaces (DeviceInfo,
NULL, &guid, iNum, &DeviceInterface) )
{
SetupDiDestroyDeviceInfoList( DeviceInfo );
return RString();
}
unsigned long iSize;
SetupDiGetDeviceInterfaceDetail( DeviceInfo, &DeviceInterface, NULL, 0, &iSize, 0 );
PSP_INTERFACE_DEVICE_DETAIL_DATA DeviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc( iSize );
DeviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
RString sRet;
if( SetupDiGetDeviceInterfaceDetail(DeviceInfo, &DeviceInterface,
DeviceDetail, iSize, &iSize, NULL) )
sRet = DeviceDetail->DevicePath;
free( DeviceDetail );
SetupDiDestroyDeviceInfoList( DeviceInfo );
return sRet;
}
bool USBDevice::Open( int iVID, int iPID, int iBlockSize, int iNum, void (*pfnInit)(HANDLE) )
{
DWORD iIndex = 0;
RString path;
while( (path = GetUSBDevicePath(iIndex++)) != "" )
{
HANDLE h = CreateFile( path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if( h == INVALID_HANDLE_VALUE )
continue;
HIDD_ATTRIBUTES attr;
if( !HidD_GetAttributes(h, &attr) )
{
CloseHandle( h );
continue;
}
if( (iVID != -1 && attr.VendorID != iVID) ||
(iPID != -1 && attr.ProductID != iPID) )
{
CloseHandle( h );
continue; /* This isn't it. */
}
/* The VID and PID match. */
if( iNum-- > 0 )
{
CloseHandle( h );
continue;
}
if( pfnInit )
pfnInit( h );
CloseHandle(h);
m_IO.Open( path, iBlockSize );
return true;
}
return false;
}
bool USBDevice::IsOpen() const
{
return m_IO.IsOpen();
}
int USBDevice::GetPadEvent()
{
if( !IsOpen() )
return -1;
long iBuf;
if( m_IO.read(&iBuf) <= 0 )
return -1;
return iBuf;
}
WindowsFileIO::WindowsFileIO()
{
ZeroMemory( &m_Overlapped, sizeof(m_Overlapped) );
m_Handle = INVALID_HANDLE_VALUE;
m_pBuffer = NULL;
}
WindowsFileIO::~WindowsFileIO()
{
if( m_Handle != INVALID_HANDLE_VALUE )
CloseHandle( m_Handle );
delete[] m_pBuffer;
}
bool WindowsFileIO::Open( RString path, int iBlockSize )
{
LOG->Trace( "WindowsFileIO::open(%s)", path.c_str() );
m_iBlockSize = iBlockSize;
if( m_pBuffer )
delete[] m_pBuffer;
m_pBuffer = new char[m_iBlockSize];
if( m_Handle != INVALID_HANDLE_VALUE )
CloseHandle( m_Handle );
m_Handle = CreateFile( path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
if( m_Handle == INVALID_HANDLE_VALUE )
return false;
queue_read();
return true;
}
void WindowsFileIO::queue_read()
{
/* Request feedback from the device. */
unsigned long iRead;
ReadFile( m_Handle, m_pBuffer, m_iBlockSize, &iRead, &m_Overlapped );
}
int WindowsFileIO::finish_read( void *p )
{
LOG->Trace( "this %p, %p", this, p );
/* We do; get the result. It'll go into the original m_pBuffer
* we supplied on the original call; that's why m_pBuffer is a
* member instead of a local. */
unsigned long iCnt;
int iRet = GetOverlappedResult( m_Handle, &m_Overlapped, &iCnt, FALSE );
if( iRet == 0 && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE) )
return -1;
queue_read();
if( iRet == 0 )
{
LOG->Warn( werr_ssprintf(GetLastError(), "Error reading USB device") );
return -1;
}
memcpy( p, m_pBuffer, iCnt );
return iCnt;
}
int WindowsFileIO::read( void *p )
{
LOG->Trace( "WindowsFileIO::read()" );
/* See if we have a response for our request (which we may
* have made on a previous call): */
if( WaitForSingleObjectEx(m_Handle, 0, TRUE) == WAIT_TIMEOUT )
return -1;
return finish_read(p);
}
int WindowsFileIO::read_several(const vector<WindowsFileIO *> &sources, void *p, int &actual, float timeout)
{
HANDLE *Handles = new HANDLE[sources.size()];
for( unsigned i = 0; i < sources.size(); ++i )
Handles[i] = sources[i]->m_Handle;
int ret = WaitForMultipleObjectsEx( sources.size(), Handles, false, int(timeout * 1000), true);
delete[] Handles;
if( ret == -1 )
{
LOG->Trace( werr_ssprintf(GetLastError(), "WaitForMultipleObjectsEx failed") );
return -1;
}
if( ret >= int(WAIT_OBJECT_0) && ret < int(WAIT_OBJECT_0+sources.size()) )
{
actual = ret - WAIT_OBJECT_0;
return sources[actual]->finish_read(p);
}
return 0;
}
bool WindowsFileIO::IsOpen() const
{
return m_Handle != INVALID_HANDLE_VALUE;
}
/*
* (c) 2002-2005 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+68
View File
@@ -0,0 +1,68 @@
/* WindowsFileIO - Windows device I/O. */
#ifndef WIN32_USB_H
#define WIN32_USB_H
#include <vector>
#include <windows.h>
class WindowsFileIO
{
public:
WindowsFileIO();
~WindowsFileIO();
bool Open( RString sPath, int iBlockSize );
bool IsOpen() const;
/* Nonblocking read. size must always be the same. Returns the number of bytes
* read, or 0. */
int read( void *p );
static int read_several( const vector<WindowsFileIO *> &sources, void *p, int &actual, float timeout );
private:
void queue_read();
int finish_read( void *p );
HANDLE m_Handle;
OVERLAPPED m_Overlapped;
char *m_pBuffer;
int m_iBlockSize;
};
/* WindowsFileIO - Windows USB I/O */
class USBDevice
{
public:
int GetPadEvent();
bool Open( int iVID, int iPID, int iBlockSize, int iNum, void (*pfnInit)(HANDLE) );
bool IsOpen() const;
WindowsFileIO m_IO;
};
#endif
/*
* (c) 2002-2005 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+147
View File
@@ -0,0 +1,147 @@
#include "global.h"
#include "VideoDriverInfo.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RegistryAccess.h"
#include <windows.h>
// this will not work on 95 and NT because of EnumDisplayDevices
RString GetPrimaryVideoName()
{
typedef BOOL (WINAPI* pfnEnumDisplayDevices)(PVOID,DWORD,PDISPLAY_DEVICE,DWORD);
pfnEnumDisplayDevices EnumDisplayDevices;
HINSTANCE hInstUser32;
hInstUser32 = LoadLibrary( "User32.DLL" );
if( !hInstUser32 )
return RString();
// VC6 don't have a stub to static link with, so link dynamically.
EnumDisplayDevices = (pfnEnumDisplayDevices)GetProcAddress(hInstUser32,"EnumDisplayDevicesA");
if( EnumDisplayDevices == NULL )
{
FreeLibrary(hInstUser32);
return RString();
}
RString sPrimaryDeviceName;
for( int i=0; true; ++i )
{
DISPLAY_DEVICE dd;
ZERO( dd );
dd.cb = sizeof(dd);
if( !EnumDisplayDevices(NULL, i, &dd, 0) )
break;
if( dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE )
{
sPrimaryDeviceName = (char*)dd.DeviceString;
break;
}
}
FreeLibrary( hInstUser32 );
TrimRight( sPrimaryDeviceName );
return sPrimaryDeviceName;
}
RString GetPrimaryVideoDriverName()
{
RString sPrimaryDeviceName = GetPrimaryVideoName();
if( sPrimaryDeviceName != "" )
return sPrimaryDeviceName;
LOG->Warn("GetPrimaryVideoName failed; renderer selection may be wrong");
VideoDriverInfo info;
if( !GetVideoDriverInfo(0, info) )
return "(ERROR DETECTING VIDEO DRIVER)";
return info.sDescription;
}
/* Get info for the given card number. Return false if that card doesn't exist. */
bool GetVideoDriverInfo( int iCardno, VideoDriverInfo &info )
{
OSVERSIONINFO version;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
const bool bIsWin9x = version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS;
static bool bInitialized=false;
static vector<RString> lst;
if( !bInitialized )
{
bInitialized = true;
const RString sTopKey = bIsWin9x?
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Class\\Display":
"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}";
RegistryAccess::GetRegSubKeys( sTopKey, lst, ".*", false );
for( int i=lst.size()-1; i >= 0; --i )
{
/* Remove all keys that aren't four characters long ("Properties"). */
if( lst[i].size() != 4 )
{
lst.erase( lst.begin()+i );
continue;
}
lst[i] = sTopKey + "\\" + lst[i];
}
if( lst.size() == 0 )
{
LOG->Warn("GetVideoDriverInfo error: no cards found!");
return false;
}
}
while( iCardno < (int)lst.size() )
{
const RString sKey = lst[iCardno];
if( !RegistryAccess::GetRegValue( sKey, "DriverDesc", info.sDescription ) )
{
/* Remove this one from the list and ignore it, */
lst.erase( lst.begin()+iCardno );
continue;
}
TrimRight( info.sDescription );
RegistryAccess::GetRegValue( sKey, "DriverDate", info.sDate );
RegistryAccess::GetRegValue( sKey, "MatchingDeviceId", info.sDeviceID );
RegistryAccess::GetRegValue( sKey, "ProviderName", info.sProvider );
RegistryAccess::GetRegValue( sKey, bIsWin9x? "Ver":"DriverVersion", info.sVersion );
return true;
}
return false;
}
/*
* (c) 2002-2004 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+44
View File
@@ -0,0 +1,44 @@
/* GetVideoDriverInfo - Get information about Win32 video drivers. */
#ifndef VIDEO_DRIVER_INFO_H
#define VIDEO_DRIVER_INFO_H
struct VideoDriverInfo
{
RString sProvider;
RString sDescription;
RString sVersion;
RString sDate;
RString sDeviceID;
};
RString GetPrimaryVideoName();
bool GetVideoDriverInfo( int iCardno, VideoDriverInfo &info );
RString GetPrimaryVideoDriverName();
#endif
/*
* (c) 2002-2004 Chris Danford, Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+130
View File
@@ -0,0 +1,130 @@
#include "global.h"
#include "archutils/Win32/WindowIcon.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageSurface_Load.h"
#include "archutils/Win32/ErrorStrings.h"
#include <wingdi.h>
HICON IconFromSurface( const RageSurface *pSrcImg )
{
RageSurface *pImg;
{
/* Round the width up to a multiple of 8, convert to 32-bit BGR, and reduce
* to one-bit alpha. */
int iWidth = pSrcImg->w;
iWidth = (iWidth+7) & ~7;
pImg = CreateSurface( iWidth, pSrcImg->h, 32,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xFF000000 );
RageSurfaceUtils::Blit( pSrcImg, pImg );
}
RageSurfaceUtils::FlipVertically( pImg );
int iSize = sizeof(BITMAPINFOHEADER);
int iSizeImage = 0;
iSizeImage += pImg->h * pImg->pitch; /* image */
iSizeImage += (pImg->h * pImg->w) / 8; /* mask */
BITMAPINFOHEADER *pBitmap = (BITMAPINFOHEADER *) malloc( iSize + iSizeImage );
memset( pBitmap, 0, iSize + iSizeImage );
pBitmap->biSize = sizeof(BITMAPINFOHEADER);
pBitmap->biWidth = pImg->w;
pBitmap->biHeight = pImg->h * 2;
pBitmap->biPlanes = 1;
pBitmap->biBitCount = 32;
pBitmap->biCompression = BI_RGB;
pBitmap->biSizeImage = pImg->h * pImg->pitch;
uint8_t *pImage = ((uint8_t *) pBitmap) + iSize;
uint8_t *pMask = pImage + pImg->h * pImg->pitch;
memcpy( pImage, pImg->pixels, pImg->h * pImg->pitch );
int iMaskPitch = pImg->w/8;
for( int y = 0; y < pImg->h; ++y )
{
int bit = 0x80;
uint32_t *pRow = (uint32_t *) (pImage + y*pImg->pitch);
uint8_t *pMaskRow = pMask + y*iMaskPitch;
for( int x = 0; x < pImg->w; ++x )
{
if( !(pRow[x] & pImg->fmt.Mask[3]) )
{
/* Transparent; set this mask bit. */
*pMaskRow |= bit;
pRow[x] = 0;
}
bit >>= 1;
if( bit == 0 )
{
bit = 0x80;
++pMaskRow;
}
}
}
HICON icon = CreateIconFromResourceEx( (BYTE *) pBitmap, iSize + iSizeImage, TRUE, 0x00030000, pImg->w, pImg->h, LR_DEFAULTCOLOR );
delete pImg;
pImg = NULL;
free( pBitmap );
if( icon == NULL )
{
LOG->Trace( "%s", werr_ssprintf( GetLastError(), "CreateIconFromResourceEx" ).c_str() );
return NULL;
}
return icon;
}
HICON IconFromFile( const RString &sIconFile )
{
RString sError;
RageSurface *pImg = RageSurfaceUtils::LoadFile( sIconFile, sError );
if( pImg == NULL )
{
LOG->Warn( "Couldn't open icon \"%s\": %s", sIconFile.c_str(), sError.c_str() );
return NULL;
}
HICON icon = IconFromSurface( pImg );
delete pImg;
return icon;
}
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+36
View File
@@ -0,0 +1,36 @@
/* Win32 helper - load an HICON */
#ifndef WINDOW_ICON_H
#define WINDOW_ICON_H
#include <windows.h>
struct RageSurface;
HICON IconFromSurface( const RageSurface *pImg );
HICON IconFromFile( const RString &sIconFile );
#endif
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+56
View File
@@ -0,0 +1,56 @@
#include "global.h"
#include "WindowsDialogBox.h"
WindowsDialogBox::WindowsDialogBox()
{
m_hWnd = NULL;
}
void WindowsDialogBox::Run( int iDialog )
{
char szFullAppPath[MAX_PATH];
GetModuleFileName( NULL, szFullAppPath, MAX_PATH );
HINSTANCE hHandle = LoadLibrary( szFullAppPath );
DialogBoxParam( hHandle, MAKEINTRESOURCE(iDialog), NULL, DlgProc, (LPARAM) this );
}
BOOL APIENTRY WindowsDialogBox::DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
if( msg == WM_INITDIALOG )
SetProp( hDlg, "WindowsDialogBox", (HANDLE) lParam );
WindowsDialogBox *pThis = (WindowsDialogBox *) GetProp( hDlg, "WindowsDialogBox" );
if( pThis == NULL )
return FALSE;
if( pThis->m_hWnd == NULL )
pThis->m_hWnd = hDlg;
return pThis->HandleMessage( msg, wParam, lParam );
}
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+50
View File
@@ -0,0 +1,50 @@
/* WindowsDialogBox - Simplifies the creation of modal Windows dialog boxes. */
#ifndef WINDOWS_DIALOG_BOX_H
#define WINDOWS_DIALOG_BOX_H
#include <windows.h>
class WindowsDialogBox
{
public:
WindowsDialogBox();
virtual ~WindowsDialogBox() { }
void Run( int iDialog );
HWND GetHwnd() { return m_hWnd; }
protected:
virtual BOOL HandleMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { return false; }
private:
static BOOL APIENTRY DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
HWND m_hWnd;
};
#endif
/*
* (c) 2006 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+60
View File
@@ -0,0 +1,60 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by WindowsResources.rc
//
#define IDC_CRASH_SAVE 16
#define IDD_ERROR_DIALOG 111
#define IDD_LOADING_DIALOG 116
#define BITMAP_LOADING 117
#define IDD_OK 118
#define IDD_DISASM_CRASH 120
#define BITMAP_CRASH 121
#define IDD_REPORT_CRASH 121
#define BITMAP_ERROR 129
#define IDC_SHOCKWAVEFLASH1 1000
#define IDC_BUTTON_RESTART 1001
#define IDM_TOGGLEFULLSCREEN 1002
#define IDC_BUTTON_REPORT 1002
#define IDM_CHANGERESOLUTION 1003
#define IDC_BUTTON_VIEW_LOG 1003
#define IDM_CHANGEDETAIL 1003
#define IDM_CHANGEDISPLAYCOLOR 1004
#define IDM_CHANGETEXTURECOLOR 1005
#define IDC_EDIT_ERROR 1005
#define IDM_TOGGLESTATISTICS 1006
#define IDI_ICON 1007
#define IDC_CURSOR 1008
#define IDC_STATIC_MESSAGE1 1010
#define IDC_STATIC_MESSAGE2 1011
#define IDC_BUTTON_CLOSE 1011
#define IDC_VIEW_LOG 1012
#define IDC_STATIC_MESSAGE3 1013
#define IDC_PROGRESS1 1014
#define IDC_PROGRESS 1014
#define IDC_HUSH 1016
#define IDC_MESSAGE 1017
#define IDC_CHECK2 1019
#define IDC_SPLASH 1020
#define IDC_STATIC_HEADER_TEXT 1021
#define IDC_STATIC_ICON 1022
#define IDC_BUTTON_AUTO_REPORT 1026
#define IDC_RESULT_ID 1028
#define IDC_MAIN_TEXT 1029
#define IDC_ASMBOX 1133
#define IDC_REGDUMP 1283
#define IDC_STATIC_BOMBREASON 1284
#define IDC_STATIC_BOMBREASON2 1285
#define IDC_CALL_STACK 1310
#define IDI_ICON1 1311
#define IDM_EXIT 40003
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 134
#define _APS_NEXT_COMMAND_VALUE 40009
#define _APS_NEXT_CONTROL_VALUE 1030
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+229
View File
@@ -0,0 +1,229 @@
// Microsoft Visual C++ generated resource script.
//
#include "WindowsResources.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ERROR_DIALOG DIALOGEX 0, 0, 332, 234
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "Fatal Error"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
CONTROL "",IDC_STATIC,"Static",SS_WHITERECT,0,0,332,35
DEFPUSHBUTTON "Close",IDOK,265,215,60,15
EDITTEXT IDC_EDIT_ERROR,5,59,320,151,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP
PUSHBUTTON "View Log",IDC_BUTTON_VIEW_LOG,8,215,74,15
PUSHBUTTON "Report Error",IDC_BUTTON_REPORT,90,215,76,15
PUSHBUTTON "Restart Game",IDC_BUTTON_RESTART,175,215,80,15
LTEXT "Specific details about the error are shown in the box below:",IDC_STATIC,7,45,319,11
LTEXT "Fatal Error",IDC_STATIC_HEADER_TEXT,5,5,249,23
ICON IDI_ICON,IDC_STATIC_ICON,296,6,21,20
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,34,332,1
END
IDD_LOADING_DIALOG DIALOG 0, 0, 312, 82
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "line1",IDC_STATIC_MESSAGE1,0,41,310,10,SS_NOPREFIX | SS_CENTERIMAGE
CTEXT "line2",IDC_STATIC_MESSAGE2,0,54,310,10,SS_NOPREFIX | SS_CENTERIMAGE
CTEXT "line3",IDC_STATIC_MESSAGE3,0,65,310,10,SS_NOPREFIX | SS_CENTERIMAGE
CONTROL "",IDC_SPLASH,"Static",SS_BITMAP,0,0,310,25
END
IDD_DISASM_CRASH DIALOGEX 0, 0, 332, 114
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
PUSHBUTTON "&View Crash Info",IDC_CRASH_SAVE,40,73,94,15
PUSHBUTTON "View &Log",IDC_VIEW_LOG,137,73,63,15
PUSHBUTTON "Report the &Error",IDC_BUTTON_REPORT,203,73,89,15
PUSHBUTTON "&Restart Game",IDC_BUTTON_RESTART,197,95,78,15
PUSHBUTTON "&Close",IDC_BUTTON_CLOSE,278,95,50,15
LTEXT "A crash has occurred. Diagnostic information has been saved to a file called ""crashinfo.txt"" in the game program directory.",IDC_STATIC,8,41,312,19
CONTROL "",IDC_STATIC,"Static",SS_WHITERECT,0,0,332,35
LTEXT "Program Crash",IDC_STATIC_HEADER_TEXT,5,5,249,23
ICON IDI_ICON,IDC_STATIC_ICON,296,6,20,20
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,34,332,1
END
IDD_OK DIALOGEX 0, 0, 336, 98
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "Prompt"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
DEFPUSHBUTTON "OK",IDOK,143,77,50,14
CONTROL "&Don't display this message again",IDC_HUSH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,63,181,10
EDITTEXT IDC_MESSAGE,7,7,322,55,ES_CENTER | ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL
END
IDD_REPORT_CRASH DIALOGEX 0, 0, 287, 98
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | DS_CENTERMOUSE | WS_POPUP | WS_CAPTION
CAPTION "Program Crash"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
PUSHBUTTON "&Send Error Report",IDC_BUTTON_AUTO_REPORT,132,79,89,15
PUSHBUTTON "&View Error Report",IDC_CRASH_SAVE,6,79,86,15
CONTROL "",IDC_PROGRESS,"msctls_progress32",NOT WS_VISIBLE | WS_BORDER,132,79,89,15
PUSHBUTTON "&Don't Send",IDC_BUTTON_CLOSE,224,79,59,15
LTEXT "The program has encountered an error. Click Send Error Report to automatically report the problem and check for updates.",IDC_MAIN_TEXT,13,48,263,18
CONTROL "",IDC_STATIC,"Static",SS_WHITERECT,0,0,287,35
LTEXT "Program Crash",IDC_STATIC_HEADER_TEXT,5,5,249,23
ICON IDI_ICON,IDC_STATIC_ICON,259,6,21,20
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,34,287,1
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_LOADING_DIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 305
TOPMARGIN, 7
BOTTOMMARGIN, 75
END
IDD_DISASM_CRASH, DIALOG
BEGIN
RIGHTMARGIN, 328
VERTGUIDE, 6
BOTTOMMARGIN, 110
HORZGUIDE, 96
END
IDD_OK, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 329
TOPMARGIN, 7
BOTTOMMARGIN, 91
END
IDD_REPORT_CRASH, DIALOG
BEGIN
RIGHTMARGIN, 283
VERTGUIDE, 6
BOTTOMMARGIN, 94
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"WindowsResources.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "smzip.ico"
IDI_ICON ICON "StepMania.ICO"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "http://www.stepmania.com"
VALUE "FileDescription", "StepMania"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "StepMania"
VALUE "LegalCopyright", "Copyright © 2001-2002"
VALUE "OriginalFilename", "StepMania.exe"
VALUE "ProductName", " StepMania"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+42
View File
@@ -0,0 +1,42 @@
#include "global.h"
#include "arch_setup.h"
#ifdef _WINDOWS
# include <windows.h>
#endif
#include "CommandLine.h"
#if defined(WINDOWS)
int main( int argc, char* argv[] );
int __stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, char *pCmdLine, int nCmdShow )
{
char **argv;
int argc = GetWin32CmdLine( argv );
return main( argc, argv );
}
#endif
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+236
View File
@@ -0,0 +1,236 @@
#ifndef ARCH_SETUP_WINDOWS_H
#define ARCH_SETUP_WINDOWS_H
#if !defined(XBOX)
#define HAVE_FFMPEG
#define HAVE_THEORA
#endif
#if !defined(XBOX)
#define SUPPORT_OPENGL
#endif
#define SUPPORT_D3D
#if defined(__MINGW32__)
#define _WINDOWS // This isn't defined under MinGW
#define NEED_CSTDLIB_WORKAROUND // Needed for llabs() in MinGW
#endif
#if defined(_MSC_VER)
#if _MSC_VER == 1400 // VC8 specific warnings
#pragma warning (disable : 4996) // deprecated functions vs "ISO C++ conformant names". (stricmp vs _stricmp)
#pragma warning (disable : 4005) // macro redefinitions (ARRAYSIZE)
#endif
#define snprintf _snprintf // Unsure if this goes with __MINGW32__ right now.
#pragma warning (disable : 4275) // non dll-interface class 'stdext::exception' used as base for dll-interface class 'std::bad_cast', bug in VC <exception> when exceptions disabled
#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)
* 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 */
#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 */
#pragma warning (disable : 4063)
#pragma warning (disable : 4127)
#pragma warning (disable : 4786) /* VC6: identifier was truncated to '255' characters in the debug information */
#pragma warning (disable : 4505) // removed unferenced local function from integer.cpp & algebra.h
#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. */
#define PATH_MAX _MAX_PATH
/* Disable false deprecation warnings in VC2005. */
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE
/* 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: */
#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. */
#define _WIN32_WINNT 0x0400
#define _WIN32_IE 0x0400
/* 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 */
#define lstat stat
#define fsync _commit
#define isnan _isnan
#define isfinite _finite
/* mkdir is missing the mode arg */
#define mkdir(p,m) mkdir(p)
typedef time_t time_t;
struct tm;
struct tm *my_localtime_r( const time_t *timep, struct tm *result );
#define localtime_r my_localtime_r
struct tm *my_gmtime_r( const time_t *timep, struct tm *result );
#define gmtime_r my_gmtime_r
void my_usleep( unsigned long usec );
#define usleep my_usleep
/* Missing stdint types: */
#if !defined(__MINGW32__) // MinGW headers define these for us
typedef signed char int8_t;
typedef signed short int16_t;
typedef int int32_t;
typedef __int64 int64_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define INT64_C(i) i##i64
#define UINT64_C(i) i##i64
static inline int64_t llabs( int64_t i ) { return i >= 0? i: -i; }
#endif
#undef min
#undef max
#define NOMINMAX /* make sure Windows doesn't try to define this */
/* Windows is missing some basic math functions: */
// But MinGW isn't.
#if !defined(__MINGW32__)
#define NEED_TRUNCF
#define NEED_ROUNDF
#define NEED_STRTOF
#define MISSING_STDINT_H
#endif
// MinGW provides us with this function already
#if !defined(__MINGW32__)
inline long int lrintf( float f )
{
int retval;
_asm fld f;
_asm fistp retval;
return retval;
}
#endif
/* For RageLog. */
#define HAVE_VERSION_INFO
/* 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
#define ENDIAN_LITTLE
#if defined(_XBOX)
#if defined(_DEBUG)
#define OGG_LIB_DIR "vorbis/xbox/debug/"
#else
#define OGG_LIB_DIR "vorbis/xbox/release/"
#endif
#else
#define OGG_LIB_DIR "vorbis/win32/"
#endif
#if defined(XBOX)
#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?
#define HAVE_BYTE_SWAPS
inline uint32_t ArchSwap32( uint32_t n )
{
__asm
{
mov eax, n
xchg al, ah
ror eax, 16
xchg al, ah
mov n, eax
};
return n;
}
inline uint32_t ArchSwap24( uint32_t n )
{
__asm
{
mov eax, n
xchg al, ah
ror eax, 16
xchg al, ah
ror eax, 8
mov n, eax
};
return n;
}
inline uint16_t ArchSwap16( uint16_t n )
{
__asm
{
mov ax, n
xchg al, ah
mov n, ax
};
return n;
}
#endif
#endif
/*
* (c) 2002-2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+55
View File
@@ -0,0 +1,55 @@
#include "global.h"
#include "arch_setup.h"
#include "RageThreads.h"
#include <time.h>
#ifdef _WINDOWS
# include <windows.h>
#endif
struct tm *my_localtime_r( const time_t *timep, struct tm *result )
{
static RageMutex mut("my_localtime_r");
LockMut(mut);
*result = *localtime( timep );
return result;
}
struct tm *my_gmtime_r( const time_t *timep, struct tm *result )
{
static RageMutex mut("my_gmtime_r");
LockMut(mut);
*result = *gmtime( timep );
return result;
}
void my_usleep( unsigned long usec )
{
::Sleep( usec/1000 );
}
/*
* (c) 2004 Glenn Maynard
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+413
View File
@@ -0,0 +1,413 @@
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
HIDSDI.H
Abstract:
This module contains the PUBLIC definitions for the
code that implements the HID dll.
Environment:
Kernel & user mode
--*/
#ifndef _HIDSDI_H
#define _HIDSDI_H
#include <pshpack4.h>
//#include "wtypes.h"
//#include <windef.h>
//#include <win32.h>
//#include <basetyps.h>
typedef LONG NTSTATUS;
#include "hidusage.h"
#include "hidpi.h"
typedef struct _HIDD_CONFIGURATION {
PVOID cookie;
ULONG size;
ULONG RingBufferSize;
} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;
typedef struct _HIDD_ATTRIBUTES {
ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
//
// Vendor ids of this hid device
//
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
//
// Additional fields will be added to the end of this structure.
//
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
BOOLEAN __stdcall
HidD_GetAttributes (
IN HANDLE HidDeviceObject,
OUT PHIDD_ATTRIBUTES Attributes
);
/*++
Routine Description:
Fill in the given HIDD_ATTRIBUTES structure with the attributes of the
given hid device.
--*/
void __stdcall
HidD_GetHidGuid (
OUT LPGUID HidGuid
);
BOOLEAN __stdcall
HidD_GetPreparsedData (
IN HANDLE HidDeviceObject,
OUT PHIDP_PREPARSED_DATA * PreparsedData
);
/*++
Routine Description:
Given a handle to a valid Hid Class Device Object, retrieve the preparsed
data for the device. This routine will allocate the appropriately
sized buffer to hold this preparsed data. It is up to client to call
HidP_FreePreparsedData to free the memory allocated to this structure when
it is no longer needed.
Arguments:
HidDeviceObject A handle to a Hid Device that the client obtains using
a call to CreateFile on a valid Hid device string name.
The string name can be obtained using standard PnP calls.
PreparsedData An opaque data structure used by other functions in this
library to retrieve information about a given device.
Return Value:
TRUE if successful.
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_FreePreparsedData (
IN PHIDP_PREPARSED_DATA PreparsedData
);
BOOLEAN __stdcall
HidD_FlushQueue (
IN HANDLE HidDeviceObject
);
/*++
Routine Description:
Flush the input queue for the given HID device.
Arguments:
HidDeviceObject A handle to a Hid Device that the client obtains using
a call to CreateFile on a valid Hid device string name.
The string name can be obtained using standard PnP calls.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetConfiguration (
IN HANDLE HidDeviceObject,
OUT PHIDD_CONFIGURATION Configuration,
IN ULONG ConfigurationLength
);
/*++
Routine Description:
Get the configuration information for this Hid device
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Configuration A configuration structure. HidD_GetConfiguration MUST
be called before the configuration can be modified and
set using HidD_SetConfiguration
ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this
parameter, we can later increase the length of the
configuration array and not break older apps.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetConfiguration (
IN HANDLE HidDeviceObject,
IN PHIDD_CONFIGURATION Configuration,
IN ULONG ConfigurationLength
);
/*++
Routine Description:
Set the configuration information for this Hid device...
NOTE: HidD_GetConfiguration must be called to retrieve the current
configuration information before this information can be modified
and set.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Configuration A configuration structure. HidD_GetConfiguration MUST
be called before the configuration can be modified and
set using HidD_SetConfiguration
ConfigurationLength That is ``sizeof (HIDD_CONFIGURATION)''. Using this
parameter, we can later increase the length of the
configuration array and not break older apps.
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetFeature (
IN HANDLE HidDeviceObject,
OUT PVOID ReportBuffer,
IN ULONG ReportBufferLength
);
/*++
Routine Description:
Retrieve a feature report from a HID device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
ReportBuffer The buffer that the feature report should be placed
into. The first byte of the buffer should be set to
the report ID of the desired report
ReportBufferLength The size (in bytes) of ReportBuffer. This value
should be greater than or equal to the
FeatureReportByteLength field as specified in the
HIDP_CAPS structure for the device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetFeature (
IN HANDLE HidDeviceObject,
IN PVOID ReportBuffer,
IN ULONG ReportBufferLength
);
/*++
Routine Description:
Send a feature report to a HID device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
ReportBuffer The buffer of the feature report to send to the device
ReportBufferLength The size (in bytes) of ReportBuffer. This value
should be greater than or equal to the
FeatureReportByteLength field as specified in the
HIDP_CAPS structure for the device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetNumInputBuffers (
IN HANDLE HidDeviceObject,
OUT PULONG NumberBuffers
);
/*++
Routine Description:
This function returns the number of input buffers used by the specified
file handle to the Hid device. Each file object has a number of buffers
associated with it to queue reports read from the device but which have
not yet been read by the user-mode app with a handle to that device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
NumberBuffers Number of buffers currently being used for this file
handle to the Hid device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_SetNumInputBuffers (
IN HANDLE HidDeviceObject,
OUT ULONG NumberBuffers
);
/*++
Routine Description:
This function sets the number of input buffers used by the specified
file handle to the Hid device. Each file object has a number of buffers
associated with it to queue reports read from the device but which have
not yet been read by the user-mode app with a handle to that device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
NumberBuffers New number of buffers to use for this file handle to
the Hid device
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetPhysicalDescriptor (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the raw physical descriptor for the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the physical
descriptor if one exists for the specified device
handle
BufferLength Length of buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetManufacturerString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the manufacturer string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the manufacturer
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetProductString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the product string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the product
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetIndexedString (
IN HANDLE HidDeviceObject,
IN ULONG StringIndex,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves a string from the specified Hid device that is
specified with a certain string index.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
StringIndex Index of the string to retrieve
Buffer Buffer which on return will contain the product
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
BOOLEAN __stdcall
HidD_GetSerialNumberString (
IN HANDLE HidDeviceObject,
OUT PVOID Buffer,
IN ULONG BufferLength
);
/*++
Routine Description:
This function retrieves the serial number string from the specified
Hid device.
Arguments:
HidDeviceObject A handle to a Hid Device Object.
Buffer Buffer which on return will contain the serial number
string returned from the device. This string is a
wide-character string
BufferLength Length of Buffer (in bytes)
Return Value:
TRUE if successful
FALSE otherwise -- Use GetLastError() to get extended error information
--*/
#include <poppack.h>
#endif
+265
View File
@@ -0,0 +1,265 @@
/*++
Copyright (c) 1996, 1997 Microsoft Corporation
Module Name:
HIDUSAGE.H
Abstract:
Public Definitions of HID USAGES.
Environment:
Kernel & user mode
--*/
#ifndef __HIDUSAGE_H__
#define __HIDUSAGE_H__
//
// Usage Pages
//
typedef USHORT USAGE, *PUSAGE;
#define HID_USAGE_PAGE_GENERIC ((USAGE) 0x01)
#define HID_USAGE_PAGE_SIMULATION ((USAGE) 0x02)
#define HID_USAGE_PAGE_VR ((USAGE) 0x03)
#define HID_USAGE_PAGE_SPORT ((USAGE) 0x04)
#define HID_USAGE_PAGE_GAME ((USAGE) 0x05)
#define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07)
#define HID_USAGE_PAGE_LED ((USAGE) 0x08)
#define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09)
#define HID_USAGE_PAGE_ORDINAL ((USAGE) 0x0A)
#define HID_USAGE_PAGE_TELEPHONY ((USAGE) 0x0B)
#define HID_USAGE_PAGE_CONSUMER ((USAGE) 0x0C)
#define HID_USAGE_PAGE_DIGITIZER ((USAGE) 0x0D)
#define HID_USAGE_PAGE_UNICODE ((USAGE) 0x10)
#define HID_USAGE_PAGE_ALPHANUMERIC ((USAGE) 0x14)
//
// Usages from Generic Desktop Page (0x01)
//
#define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01)
#define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02)
#define HID_USAGE_GENERIC_JOYSTICK ((USAGE) 0x04)
#define HID_USAGE_GENERIC_GAMEPAD ((USAGE) 0x05)
#define HID_USAGE_GENERIC_KEYBOARD ((USAGE) 0x06)
#define HID_USAGE_GENERIC_KEYPAD ((USAGE) 0x07)
#define HID_USAGE_GENERIC_SYSTEM_CTL ((USAGE) 0x80)
#define HID_USAGE_GENERIC_X ((USAGE) 0x30)
#define HID_USAGE_GENERIC_Y ((USAGE) 0x31)
#define HID_USAGE_GENERIC_Z ((USAGE) 0x32)
#define HID_USAGE_GENERIC_RX ((USAGE) 0x33)
#define HID_USAGE_GENERIC_RY ((USAGE) 0x34)
#define HID_USAGE_GENERIC_RZ ((USAGE) 0x35)
#define HID_USAGE_GENERIC_SLIDER ((USAGE) 0x36)
#define HID_USAGE_GENERIC_DIAL ((USAGE) 0x37)
#define HID_USAGE_GENERIC_WHEEL ((USAGE) 0x38)
#define HID_USAGE_GENERIC_HATSWITCH ((USAGE) 0x39)
#define HID_USAGE_GENERIC_COUNTED_BUFFER ((USAGE) 0x3A)
#define HID_USAGE_GENERIC_BYTE_COUNT ((USAGE) 0x3B)
#define HID_USAGE_GENERIC_MOTION_WAKEUP ((USAGE) 0x3C)
#define HID_USAGE_GENERIC_VX ((USAGE) 0x40)
#define HID_USAGE_GENERIC_VY ((USAGE) 0x41)
#define HID_USAGE_GENERIC_VZ ((USAGE) 0x42)
#define HID_USAGE_GENERIC_VBRX ((USAGE) 0x43)
#define HID_USAGE_GENERIC_VBRY ((USAGE) 0x44)
#define HID_USAGE_GENERIC_VBRZ ((USAGE) 0x45)
#define HID_USAGE_GENERIC_VNO ((USAGE) 0x46)
#define HID_USAGE_GENERIC_SYSCTL_POWER ((USAGE) 0x81)
#define HID_USAGE_GENERIC_SYSCTL_SLEEP ((USAGE) 0x82)
#define HID_USAGE_GENERIC_SYSCTL_WAKE ((USAGE) 0x83)
#define HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU ((USAGE) 0x84)
#define HID_USAGE_GENERIC_SYSCTL_MAIN_MENU ((USAGE) 0x85)
#define HID_USAGE_GENERIC_SYSCTL_APP_MENU ((USAGE) 0x86)
#define HID_USAGE_GENERIC_SYSCTL_HELP_MENU ((USAGE) 0x87)
#define HID_USAGE_GENERIC_SYSCTL_MENU_EXIT ((USAGE) 0x88)
#define HID_USAGE_GENERIC_SYSCTL_MENU_SELECT ((USAGE) 0x89)
#define HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT ((USAGE) 0x8A)
#define HID_USAGE_GENERIC_SYSCTL_MENU_LEFT ((USAGE) 0x8B)
#define HID_USAGE_GENERIC_SYSCTL_MENU_UP ((USAGE) 0x8C)
#define HID_USAGE_GENERIC_SYSCTL_MENU_DOWN ((USAGE) 0x8D)
//
// Usages from Simulation Controls Page (0x02)
//
#define HID_USAGE_SIMULATION_RUDDER ((USAGE) 0xBA)
#define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB)
//
// Virtual Reality Controls Page (0x03)
//
//
// Sport Controls Page (0x04)
//
//
// Game Controls Page (0x05)
//
//
// Keyboard/Keypad Page (0x07)
//
// Error "keys"
#define HID_USAGE_KEYBOARD_NOEVENT ((USAGE) 0x00)
#define HID_USAGE_KEYBOARD_ROLLOVER ((USAGE) 0x01)
#define HID_USAGE_KEYBOARD_POSTFAIL ((USAGE) 0x02)
#define HID_USAGE_KEYBOARD_UNDEFINED ((USAGE) 0x03)
// Letters
#define HID_USAGE_KEYBOARD_aA ((USAGE) 0x04)
#define HID_USAGE_KEYBOARD_zZ ((USAGE) 0x1D)
// Numbers
#define HID_USAGE_KEYBOARD_ONE ((USAGE) 0x1E)
#define HID_USAGE_KEYBOARD_ZERO ((USAGE) 0x27)
// Modifier Keys
#define HID_USAGE_KEYBOARD_LCTRL ((USAGE) 0xE0)
#define HID_USAGE_KEYBOARD_LSHFT ((USAGE) 0xE1)
#define HID_USAGE_KEYBOARD_LALT ((USAGE) 0xE2)
#define HID_USAGE_KEYBOARD_LGUI ((USAGE) 0xE3)
#define HID_USAGE_KEYBOARD_RCTRL ((USAGE) 0xE4)
#define HID_USAGE_KEYBOARD_RSHFT ((USAGE) 0xE5)
#define HID_USAGE_KEYBOARD_RALT ((USAGE) 0xE6)
#define HID_USAGE_KEYBOARD_RGUI ((USAGE) 0xE7)
#define HID_USAGE_KEYBOARD_SCROLL_LOCK ((USAGE) 0x47)
#define HID_USAGE_KEYBOARD_NUM_LOCK ((USAGE) 0x53)
#define HID_USAGE_KEYBOARD_CAPS_LOCK ((USAGE) 0x39)
// Funtion keys
#define HID_USAGE_KEYBOARD_F1 ((USAGE) 0x3A)
#define HID_USAGE_KEYBOARD_F12 ((USAGE) 0x45)
#define HID_USAGE_KEYBOARD_RETURN ((USAGE) 0x28)
#define HID_USAGE_KEYBOARD_ESCAPE ((USAGE) 0x29)
#define HID_USAGE_KEYBOARD_DELETE ((USAGE) 0x2A)
#define HID_USAGE_KEYBOARD_PRINT_SCREEN ((USAGE) 0x46)
// and hundreds more...
//
// LED Page (0x08)
//
#define HID_USAGE_LED_NUM_LOCK ((USAGE) 0x01)
#define HID_USAGE_LED_CAPS_LOCK ((USAGE) 0x02)
#define HID_USAGE_LED_SCROLL_LOCK ((USAGE) 0x03)
#define HID_USAGE_LED_COMPOSE ((USAGE) 0x04)
#define HID_USAGE_LED_KANA ((USAGE) 0x05)
#define HID_USAGE_LED_POWER ((USAGE) 0x06)
#define HID_USAGE_LED_SHIFT ((USAGE) 0x07)
#define HID_USAGE_LED_DO_NOT_DISTURB ((USAGE) 0x08)
#define HID_USAGE_LED_MUTE ((USAGE) 0x09)
#define HID_USAGE_LED_TONE_ENABLE ((USAGE) 0x0A)
#define HID_USAGE_LED_HIGH_CUT_FILTER ((USAGE) 0x0B)
#define HID_USAGE_LED_LOW_CUT_FILTER ((USAGE) 0x0C)
#define HID_USAGE_LED_EQUALIZER_ENABLE ((USAGE) 0x0D)
#define HID_USAGE_LED_SOUND_FIELD_ON ((USAGE) 0x0E)
#define HID_USAGE_LED_SURROUND_FIELD_ON ((USAGE) 0x0F)
#define HID_USAGE_LED_REPEAT ((USAGE) 0x10)
#define HID_USAGE_LED_STEREO ((USAGE) 0x11)
#define HID_USAGE_LED_SAMPLING_RATE_DETECT ((USAGE) 0x12)
#define HID_USAGE_LED_SPINNING ((USAGE) 0x13)
#define HID_USAGE_LED_CAV ((USAGE) 0x14)
#define HID_USAGE_LED_CLV ((USAGE) 0x15)
#define HID_USAGE_LED_RECORDING_FORMAT_DET ((USAGE) 0x16)
#define HID_USAGE_LED_OFF_HOOK ((USAGE) 0x17)
#define HID_USAGE_LED_RING ((USAGE) 0x18)
#define HID_USAGE_LED_MESSAGE_WAITING ((USAGE) 0x19)
#define HID_USAGE_LED_DATA_MODE ((USAGE) 0x1A)
#define HID_USAGE_LED_BATTERY_OPERATION ((USAGE) 0x1B)
#define HID_USAGE_LED_BATTERY_OK ((USAGE) 0x1C)
#define HID_USAGE_LED_BATTERY_LOW ((USAGE) 0x1D)
#define HID_USAGE_LED_SPEAKER ((USAGE) 0x1E)
#define HID_USAGE_LED_HEAD_SET ((USAGE) 0x1F)
#define HID_USAGE_LED_HOLD ((USAGE) 0x20)
#define HID_USAGE_LED_MICROPHONE ((USAGE) 0x21)
#define HID_USAGE_LED_COVERAGE ((USAGE) 0x22)
#define HID_USAGE_LED_NIGHT_MODE ((USAGE) 0x23)
#define HID_USAGE_LED_SEND_CALLS ((USAGE) 0x24)
#define HID_USAGE_LED_CALL_PICKUP ((USAGE) 0x25)
#define HID_USAGE_LED_CONFERENCE ((USAGE) 0x26)
#define HID_USAGE_LED_STAND_BY ((USAGE) 0x27)
#define HID_USAGE_LED_CAMERA_ON ((USAGE) 0x28)
#define HID_USAGE_LED_CAMERA_OFF ((USAGE) 0x29)
#define HID_USAGE_LED_ON_LINE ((USAGE) 0x2A)
#define HID_USAGE_LED_OFF_LINE ((USAGE) 0x2B)
#define HID_USAGE_LED_BUSY ((USAGE) 0x2C)
#define HID_USAGE_LED_READY ((USAGE) 0x2D)
#define HID_USAGE_LED_PAPER_OUT ((USAGE) 0x2E)
#define HID_USAGE_LED_PAPER_JAM ((USAGE) 0x2F)
#define HID_USAGE_LED_REMOTE ((USAGE) 0x30)
#define HID_USAGE_LED_FORWARD ((USAGE) 0x31)
#define HID_USAGE_LED_REVERSE ((USAGE) 0x32)
#define HID_USAGE_LED_STOP ((USAGE) 0x33)
#define HID_USAGE_LED_REWIND ((USAGE) 0x34)
#define HID_USAGE_LED_FAST_FORWARD ((USAGE) 0x35)
#define HID_USAGE_LED_PLAY ((USAGE) 0x36)
#define HID_USAGE_LED_PAUSE ((USAGE) 0x37)
#define HID_USAGE_LED_RECORD ((USAGE) 0x38)
#define HID_USAGE_LED_ERROR ((USAGE) 0x39)
#define HID_USAGE_LED_SELECTED_INDICATOR ((USAGE) 0x3A)
#define HID_USAGE_LED_IN_USE_INDICATOR ((USAGE) 0x3B)
#define HID_USAGE_LED_MULTI_MODE_INDICATOR ((USAGE) 0x3C)
#define HID_USAGE_LED_INDICATOR_ON ((USAGE) 0x3D)
#define HID_USAGE_LED_INDICATOR_FLASH ((USAGE) 0x3E)
#define HID_USAGE_LED_INDICATOR_SLOW_BLINK ((USAGE) 0x3F)
#define HID_USAGE_LED_INDICATOR_FAST_BLINK ((USAGE) 0x40)
#define HID_USAGE_LED_INDICATOR_OFF ((USAGE) 0x41)
#define HID_USAGE_LED_FLASH_ON_TIME ((USAGE) 0x42)
#define HID_USAGE_LED_SLOW_BLINK_ON_TIME ((USAGE) 0x43)
#define HID_USAGE_LED_SLOW_BLINK_OFF_TIME ((USAGE) 0x44)
#define HID_USAGE_LED_FAST_BLINK_ON_TIME ((USAGE) 0x45)
#define HID_USAGE_LED_FAST_BLINK_OFF_TIME ((USAGE) 0x46)
#define HID_USAGE_LED_INDICATOR_COLOR ((USAGE) 0x47)
#define HID_USAGE_LED_RED ((USAGE) 0x48)
#define HID_USAGE_LED_GREEN ((USAGE) 0x49)
#define HID_USAGE_LED_AMBER ((USAGE) 0x4A)
#define HID_USAGE_LED_GENERIC_INDICATOR ((USAGE) 0x3B)
//
// Button Page (0x09)
//
// There is no need to label these usages.
//
//
// Ordinal Page (0x0A)
//
// There is no need to label these usages.
//
//
// Telephony Device Page (0x0B)
//
#define HID_USAGE_TELEPHONY_PHONE ((USAGE) 0x01)
#define HID_USAGE_TELEPHONY_ANSWERING_MACHINE ((USAGE) 0x02)
#define HID_USAGE_TELEPHONY_MESSAGE_CONTROLS ((USAGE) 0x03)
#define HID_USAGE_TELEPHONY_HANDSET ((USAGE) 0x04)
#define HID_USAGE_TELEPHONY_HEADSET ((USAGE) 0x05)
#define HID_USAGE_TELEPHONY_KEYPAD ((USAGE) 0x06)
#define HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON ((USAGE) 0x07)
//
// and others...
//
#endif
File diff suppressed because it is too large Load Diff
Binary file not shown.
+330
View File
@@ -0,0 +1,330 @@
// mapconv - symbolic debugging info generator for VirtualDub
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_CNAMBUF (0x20000)
#define MAX_FNAMBUF (0x800000)
#define MAX_SEGMENTS (64)
#define MAX_GROUPS (64)
struct RVAEnt {
long rva;
char *line;
};
std::vector<RVAEnt> rvabuf;
char fnambuf[MAX_FNAMBUF];
char *fnamptr = fnambuf;
long segbuf[MAX_SEGMENTS][2];
int segcnt=0;
int seggrp[MAX_SEGMENTS];
long grpstart[MAX_GROUPS];
char line[8192];
long codeseg_flags = 0;
FILE *f, *fo;
char *strtack(char *s, const char *t, const char *s_max) {
while(s < s_max && (*s = *t))
++s, ++t;
if (s == s_max)
return NULL;
return s+1;
}
bool readline() {
if (!fgets(line, sizeof line, f))
return false;
int l = strlen(line);
if (l>0 && line[l-1]=='\n')
line[l-1]=0;
return true;
}
bool findline(const char *searchstr) {
while(readline()) {
if (strstr(line, searchstr))
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////
/* dbghelp UnDecorateSymbolName() doesn't handle anonymous namespaces,
* which look like "?A0x30dd143a". Remove "@?A0x????????"; we don't
* want to see "<anonymous namespace>::" in crash dump output, anyway. */
void RemoveAnonymousNamespaces( char *p )
{
while( p = strstr( p, "@?A" ) )
{
int skip = 0, i;
if( strlen(p) < 13 )
break;
for( i = 5; i < 13; ++i )
if( !isxdigit(p[i]) )
skip = 1;
if( p[3] != '0' || p[4] != 'x' )
skip = 1;
if( skip )
{
++p;
continue;
}
memmove( p, p+13, strlen(p+13)+1 );
}
}
void parsename(long rva, char *func_name) {
RemoveAnonymousNamespaces( func_name );
fnamptr = strtack(fnamptr, func_name, fnambuf+MAX_FNAMBUF);
if(!fnamptr)
throw "Too many func names; increase MAX_FNAMBUF.";
}
struct RVASorter {
bool operator()(const RVAEnt& e1, const RVAEnt& e2) {
return e1.rva < e2.rva;
}
};
int main(int argc, char **argv) {
int ver=0;
int i;
long load_addr;
if (argc<3) {
printf("mapconv <listing-file> <output-name>\n");
return 0;
}
if (f=fopen("version.bin", "rb")) {
fread(&ver,4,1,f);
fclose(f);
} else {
printf("can't read version file\n");
return 20;
}
if (!(f=fopen(argv[1], "r"))) {
printf("can't open listing file \"%s\"\n", argv[1]);
return 20;
}
if (!(fo=fopen(argv[2], "wb"))) {
printf("can't open output file \"%s\"\n", argv[2]);
return 20;
}
// Begin parsing file
try {
line[0] = 0;
// printf("Looking for segment list.\n");
if (!findline("Start Length"))
throw "can't find segment list";
// printf("Reading in segment list.\n");
while(readline()) {
long grp, start, len;
if (3!=sscanf(line, "%lx:%lx %lx", &grp, &start, &len))
break;
if (strstr(line+49, "CODE")) {
// printf("%04x:%08lx %08lx type code\n", grp, start, len);
codeseg_flags |= 1<<grp;
segbuf[segcnt][0] = start;
segbuf[segcnt][1] = len;
seggrp[segcnt] = grp;
++segcnt;
}
}
// printf("Looking for public symbol list.\n");
if (!findline("Publics by Value"))
throw "Can't find public symbol list.";
readline();
// printf("Found public symbol list.\n");
while(readline()) {
long grp, start, rva;
char symname[2048];
int i;
if (4!=sscanf(line, "%lx:%lx %s %lx", &grp, &start, symname, &rva))
break;
if (!(codeseg_flags & (1<<grp)) && strcmp(symname, "___ImageBase") )
continue;
RVAEnt entry = { rva, strdup(line) };
rvabuf.push_back(entry);
// parsename(rva,symname);
}
// printf("Looking for static symbol list.\n");
if (!findline("Static symbols"))
printf("WARNING: No static symbols found!\n");
else {
readline();
while(readline()) {
long grp, start, rva;
char symname[4096];
if (4!=sscanf(line, "%lx:%lx %s %lx", &grp, &start, symname, &rva))
break;
if (!(codeseg_flags & (1<<grp)))
continue;
RVAEnt entry = { rva, strdup(line) };
rvabuf.push_back(entry);
// parsename(rva,symname);
}
}
// printf("Sorting RVA entries...\n");
std::sort(rvabuf.begin(), rvabuf.end(), RVASorter());
// printf("Processing RVA entries...\n");
for(i=0; i<rvabuf.size(); i++) {
long grp, start, rva;
char symname[4096];
sscanf(rvabuf[i].line, "%lx:%lx %s %lx", &grp, &start, symname, &rva);
grpstart[grp] = rva - start;
parsename(rva, symname);
}
// printf("Processing segment entries...\n");
for(i=0; i<segcnt; i++) {
segbuf[i][0] += grpstart[seggrp[i]];
// printf("\t#%-2d %08lx-%08lx\n", i+1, segbuf[i][0], segbuf[i][0]+segbuf[i][1]-1);
}
/*
printf("Raw statistics:\n");
printf("\tRVA bytes: %ld\n", rvabuf.size()*4);
printf("\tFunc name bytes: %ld\n", fnamptr - fnambuf);
printf("\nPacking RVA data..."); fflush(stdout);
*/
std::vector<RVAEnt>::iterator itRVA = rvabuf.begin(), itRVAEnd = rvabuf.end();
std::vector<char> rvaout;
long firstrva = (*itRVA++).rva;
long lastrva = firstrva;
for(; itRVA != itRVAEnd; ++itRVA) {
long rvadiff = (*itRVA).rva - lastrva;
lastrva += rvadiff;
if (rvadiff & 0xF0000000) rvaout.push_back((char)(0x80 | ((rvadiff>>28) & 0x7F)));
if (rvadiff & 0xFFE00000) rvaout.push_back((char)(0x80 | ((rvadiff>>21) & 0x7F)));
if (rvadiff & 0xFFFFC000) rvaout.push_back((char)(0x80 | ((rvadiff>>14) & 0x7F)));
if (rvadiff & 0xFFFFFF80) rvaout.push_back((char)(0x80 | ((rvadiff>> 7) & 0x7F)));
rvaout.push_back((char)(rvadiff & 0x7F));
}
// printf("%ld bytes\n", rvaout.size());
// dump data
static const char header[64]="symbolic debug information\r\n\x1A";
fwrite(header, 64, 1, fo);
long t;
t = ver;
fwrite(&t, 4, 1, fo);
t = rvaout.size() + 4;
fwrite(&t, 4, 1, fo);
t = fnamptr - fnambuf;
fwrite(&t, 4, 1, fo);
t = segcnt;
fwrite(&t, 4, 1, fo);
fwrite(&firstrva, 4, 1, fo);
fwrite(&rvaout[0], rvaout.size(), 1, fo);
fwrite(fnambuf, fnamptr - fnambuf, 1, fo);
fwrite(segbuf, segcnt*8, 1, fo);
// really all done
if (fclose(fo))
throw "output file close failed";
} catch(const char *s) {
fprintf(stderr, "%s: %s\n", argv[1], s);
}
fclose(f);
return 0;
}
/*
* (c) 2002 Avery Lee
* 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
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* 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
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 7.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapconv", "mapconv.vcproj", "{46C1AA00-F02C-4E0A-8150-542C9728474C}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
ConfigName.0 = Debug
ConfigName.1 = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Debug.ActiveCfg = Debug|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Debug.Build.0 = Debug|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Release.ActiveCfg = Release|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
+132
View File
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="mapconv"
ProjectGUID="{46C1AA00-F02C-4E0A-8150-542C9728474C}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mapconv.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/mapconv.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="4"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/mapconv.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\mapconv.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

+54
View File
@@ -0,0 +1,54 @@
// Ehhh....
//
// I think I'll just put this one in the public domain
// (with no warranty as usual).
//
// --Avery
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
typedef unsigned long ulong;
int main(void) {
FILE *f;
ulong build=0,build_t;
char s[25];
time_t tm;
struct tm *ptm;
//////////////
if (f=fopen("version.bin","rb")) {
if (1==fread(&build_t,sizeof build_t,1,f))
build=build_t;
}
++build;
// printf("Incrementing to build %d\n",build);
time(&tm);
//memcpy(version_time, asctime(localtime(&tm)), sizeof(version_time)-1);
ptm = localtime(&tm);
strftime(s, sizeof(s), "%Y%m%d", ptm);
s[sizeof(s)-1]=0;
if (f=fopen("verstub.cpp","w")) {
fprintf(f,
"unsigned long version_num = %ld;\n"
"extern const char *const version_time = \"%s\";\n"
,build
,s);
fclose(f);
}
if (f=fopen("version.bin","wb")) {
fwrite(&build,sizeof build,1,f);
fclose(f);
}
return 0;
}
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapconv", "verinc.vcproj", "{46C1AA00-F02C-4E0A-8150-542C9728474C}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Debug.ActiveCfg = Debug|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Debug.Build.0 = Debug|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Release.ActiveCfg = Release|Win32
{46C1AA00-F02C-4E0A-8150-542C9728474C}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
+144
View File
@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="verinc"
ProjectGUID="{46C1AA00-F02C-4E0A-8150-542C9728474C}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/verinc.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/verinc.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="4"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/verinc.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\verinc.c">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>