diff options
Diffstat (limited to 'utils/smp/smp.cpp')
| -rw-r--r-- | utils/smp/smp.cpp | 1441 |
1 files changed, 1441 insertions, 0 deletions
diff --git a/utils/smp/smp.cpp b/utils/smp/smp.cpp new file mode 100644 index 0000000..fb30df9 --- /dev/null +++ b/utils/smp/smp.cpp @@ -0,0 +1,1441 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// smp.cpp : Main window procedure +// + +#include "stdafx.h" +#include "resource.h" +#include "initguid.h" +#include "CWMPHost.h" +#include <commctrl.h> +#include <windows.h> +#include <psapi.h> +#include <math.h> +#include <cstdio> +#include <vector> +#include <string> +#include <strstream> +#include <fstream> + + +#include "IceKey.h" + + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + + +#define ID_SKIP_FADE_TIMER 1 +#define ID_DRAW_TIMER 2 + + +const float FADE_TIME = 1.0f; +const int MAX_BLUR_STEPS = 100; + +HINSTANCE g_hInstance; +HWND g_hBlackFadingWindow = 0; +bool g_bFadeIn = true; +bool g_bFrameCreated = false; +CWMPHost g_frame; +CWMPHost *g_pFrame = NULL; +HDC g_hdcCapture = 0; +HDC g_hdcBlend = 0; +HBITMAP g_hbmCapture = 0; +HBITMAP g_hbmBlend = 0; +HMONITOR g_hMonitor = 0; + +int g_screenWidth = 0; +int g_screenHeight = 0; + +LPTSTR g_lpCommandLine = NULL; +std::string g_redirectTarget; +std::string g_URL; +bool g_bReportStats = false; +bool g_bUseLocalSteamServer = false; + +double g_timeAtFadeStart = 0.0; +int g_nBlurSteps = 0; + + +void LogPlayerEvent( EventType_t e ); + + +enum OSVersion +{ + OSV_95, + OSV_95OSR2, + OSV_98, + OSV_98SE, + OSV_ME, + OSV_NT4, + OSV_2000, + OSV_SERVER2003, + OSV_XP, + OSV_XPSP1, + OSV_XPSP2, + OSV_XPSP3, + OSV_VISTA, + OSV_UNKNOWN, +}; + +OSVersion DetectOSVersion() +{ + OSVERSIONINFO version; + version.dwOSVersionInfoSize = sizeof( version ); + GetVersionEx( &version ); + if ( version.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS ) + { + if ( version.dwMajorVersion != 4 ) + return OSV_UNKNOWN; + + switch ( version.dwMinorVersion ) + { + case 0: + return strstr( version.szCSDVersion, _TEXT( " C" ) ) == version.szCSDVersion ? OSV_95OSR2 : OSV_95; + case 10: + return ( strstr( version.szCSDVersion, _TEXT( " A" ) ) == version.szCSDVersion ) || ( strstr( version.szCSDVersion, _TEXT( " B" ) ) == version.szCSDVersion ) ? OSV_98SE : OSV_98; + case 90: + return OSV_ME; + } + } + else if ( version.dwPlatformId & VER_PLATFORM_WIN32_NT ) + { + if ( version.dwMajorVersion == 4 ) + return OSV_NT4; // or mabye NT3.5??? + + if ( version.dwMajorVersion == 6 ) + return OSV_VISTA; + + if ( version.dwMajorVersion != 5 ) + return OSV_UNKNOWN; + + switch ( version.dwMinorVersion ) + { + case 0: + return OSV_2000; + case 1: + { + if ( version.szCSDVersion == NULL ) + return OSV_XP; + + if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 1" ) ) != NULL ) + return OSV_XPSP1; + + if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 2" ) ) != NULL ) + return OSV_XPSP2; + + if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 3" ) ) != NULL ) + return OSV_XPSP3; + } + case 2: + return OSV_SERVER2003; // or maybe XP64??? + } + } + + return OSV_UNKNOWN; +} + +const OSVersion g_osVersion = DetectOSVersion(); + + + +#define BLUR + +#define USE_D3D8 +#ifdef USE_D3D8 + +#include <d3d8.h> +IDirect3D8* g_pD3D = NULL; +IDirect3DDevice8* g_pd3dDevice = NULL; +IDirect3DVertexBuffer8* g_pDrawVB = NULL; +IDirect3DTexture8* g_pImg = NULL; +int g_nDrawStride = 0; +DWORD g_dwDrawFVF = 0; + +#ifdef BLUR + +int g_nBlurStride = 0; +DWORD g_dwBlurFVF = 0; +IDirect3DVertexBuffer8* g_pBlurVB = NULL; +IDirect3DTexture8* g_pTex = NULL; +IDirect3DTexture8* g_pRT = NULL; +IDirect3DSurface8* g_pBackBuf = NULL; + +#endif // BLUR + +#endif // USE_D3D8 + + +DWORD g_dwUseVMROverlayOldValue = 0; +bool g_bUseVMROverlayValueExists = false; + + +void SetRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwValue, DWORD &dwOldValue, bool &bValueExisted ) +{ + HKEY hKey = 0; + LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); + if ( rval != ERROR_SUCCESS ) + { + OutputDebugString( "unable to open registry key: " ); + OutputDebugString( pKeyName ); + OutputDebugString( "\n" ); + return; + } + + DWORD dwType = 0; + DWORD dwSize = sizeof( dwOldValue ); + + // amusingly enough, if pValueName doesn't exist, RegQueryValueEx returns ERROR_FILE_NOT_FOUND + rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )&dwOldValue, &dwSize ); + bValueExisted = ( rval == ERROR_SUCCESS ); + + rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwValue, sizeof( dwValue ) ); + if ( rval != ERROR_SUCCESS ) + { + OutputDebugString( "unable to write registry value " ); + OutputDebugString( pValueName ); + OutputDebugString( " in key " ); + OutputDebugString( pKeyName ); + OutputDebugString( "\n" ); + } + + RegCloseKey( hKey ); +} + +void RestoreRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwOldValue, bool bValueExisted ) +{ + HKEY hKey = 0; + LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); + if ( rval != ERROR_SUCCESS ) + { + OutputDebugString( "unable to open registry key: " ); + OutputDebugString( pKeyName ); + OutputDebugString( "\n" ); + return; + } + + if ( bValueExisted ) + { + rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwOldValue, sizeof( dwOldValue ) ); + } + else + { + rval = RegDeleteValue( hKey, pValueName ); + } + if ( rval != ERROR_SUCCESS ) + { + OutputDebugString( "SetRegistryValue FAILED!\n" ); + } + + RegCloseKey( hKey ); +} + +bool GetRegistryString( const char *pKeyName, const char *pValueName, const char *pValueString, int nValueLen ) +{ + HKEY hKey = 0; + LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); + if ( rval != ERROR_SUCCESS ) + { + OutputDebugString( "unable to open registry key: " ); + OutputDebugString( pKeyName ); + OutputDebugString( "\n" ); + return false; + } + + DWORD dwType = 0; + rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )pValueString, ( DWORD* )&nValueLen ); + + RegCloseKey( hKey ); + + if ( rval != ERROR_SUCCESS || dwType != REG_SZ ) + { + OutputDebugString( "unable to read registry string: " ); + OutputDebugString( pValueName ); + OutputDebugString( "\n" ); + return false; + } + + return true; +} + +struct EventData_t +{ + EventData_t( int t, float pos, EventType_t e ) + : time( t ), position( pos ), event( e ) + { + } + int time; // real time + float position; // movie position + EventType_t event; // event type +}; + +const char *GetEventName( EventType_t event ) +{ + switch ( event ) + { + case ET_APPLAUNCH: return "al"; + case ET_APPEXIT: return "ae"; + case ET_CLOSE: return "cl"; + case ET_FADEOUT: return "fo"; + + case ET_MEDIABEGIN: return "mb"; + case ET_MEDIAEND: return "me"; + + case ET_JUMPHOME: return "jh"; + case ET_JUMPEND: return "je"; + + case ET_PLAY: return "pl"; + case ET_PAUSE: return "ps"; + case ET_STOP: return "st"; + case ET_SCRUBFROM: return "jf"; + case ET_SCRUBTO: return "jt"; + case ET_STEPFWD: return "sf"; + case ET_STEPBCK: return "sb"; + case ET_JUMPFWD: return "jf"; + case ET_JUMPBCK: return "jb"; + case ET_REPEAT: return "rp"; + + case ET_MAXIMIZE: return "mx"; + case ET_MINIMIZE: return "mn"; + case ET_RESTORE: return "rs"; + + default: return "<unknown>"; + } +} + +std::vector< EventData_t > g_events; + +void LogPlayerEvent( EventType_t e, float pos ) +{ + if ( !g_bReportStats ) + return; + + static int s_firstTick = GetTickCount(); + int time = GetTickCount() - s_firstTick; + +#if 0 + char msg[ 256 ]; + sprintf( msg, "event %s at time %d and pos %d\n", GetEventName( e ), time, int( 1000 * pos ) ); + OutputDebugString( msg ); +#endif + + bool bDropEvent = false; + + int nEvents = g_events.size(); + if ( ( e == ET_STEPFWD || e == ET_STEPBCK ) && nEvents >= 2 ) + { + const EventData_t &e1 = g_events[ nEvents - 1 ]; + const EventData_t &e2 = g_events[ nEvents - 2 ]; + if ( ( e1.event == e || e1.event == ET_REPEAT ) && e2.event == e ) + { + // only store starting and ending stepfwd or stepbck events, since there can be so many + // also keep events that are more than a second apart + if ( e1.event == ET_REPEAT ) + { + // keep dropping events while e1 isn't before a gap + bDropEvent = time - e1.time < 1000; + } + else + { + // e2 was kept last time, so keep e1 if e2 was kept because it was before a gap + bDropEvent = e1.time - e2.time < 1000; + } + } + } + + if ( bDropEvent ) + { + g_events[ nEvents - 1 ] = EventData_t( time, pos, ET_REPEAT ); + } + else + { + g_events.push_back( EventData_t( time, pos, e ) ); + } +} + +char C2M_UPLOADDATA = 'q'; +char C2M_UPLOADDATA_PROTOCOL_VERSION = 1; +char C2M_UPLOADDATA_DATA_VERSION = 1; + +inline void WriteHexDigit( std::ostream &os, byte src ) +{ + os.put( ( src <= 9 ) ? src + '0' : src - 10 + 'A' ); +} + +inline void WriteByte( std::ostream &os, byte src ) +{ + WriteHexDigit( os, src >> 4 ); + WriteHexDigit( os, src & 0xf ); +} + +inline void WriteShort( std::ostream &os, unsigned short src ) +{ + WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) ); + WriteByte( os, ( byte )( src & 0xff ) ); +} + +inline void WriteInt24( std::ostream &os, int src ) +{ + WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) ); + WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) ); + WriteByte( os, ( byte )( src & 0xff ) ); +} + +inline void WriteInt( std::ostream &os, int src ) +{ + WriteByte( os, ( byte )( ( src >> 24 ) & 0xff ) ); + WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) ); + WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) ); + WriteByte( os, ( byte )( src & 0xff ) ); +} + +inline void WriteFloat( std::ostream &os, float src ) +{ + WriteInt( os, *( int* )&src ); +} + +void WriteUUID( std::ostream &os, const UUID &uuid ) +{ + WriteInt( os, uuid.Data1 ); + WriteShort( os, uuid.Data2 ); + WriteShort( os, uuid.Data3 ); + for ( int i = 0; i < 8; ++i ) + { + WriteByte( os, uuid.Data4[ i ] ); + } +} + +bool QueryOrGenerateUserID( UUID &userId ) +{ + HKEY hKey = 0; + LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Steam", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); + if ( rval != ERROR_SUCCESS ) + { + UuidCreate( &userId ); + return false; + } + + DWORD dwType = 0; + unsigned char idstr[ 40 ]; + DWORD dwSize = sizeof( idstr ); + + rval = RegQueryValueEx( hKey, "smpid", NULL, &dwType, ( LPBYTE )idstr, &dwSize ); + if ( rval != ERROR_SUCCESS || dwType != REG_SZ ) + { + UuidCreate( &userId ); + + unsigned char *outstring = NULL; + UuidToString( &userId, &outstring ); + if ( outstring == NULL || *outstring == '\0' ) + { + RegCloseKey( hKey ); + return false; + } + + rval = RegSetValueEx( hKey, "smpid", 0, REG_SZ, ( CONST BYTE* )outstring, sizeof( idstr ) ); + + RpcStringFree( &outstring ); + RegCloseKey( hKey ); + + return rval == ERROR_SUCCESS; + } + + if ( RPC_S_OK != UuidFromString( idstr, &userId ) ) + return false; + + RegCloseKey( hKey ); + return true; +} + +void PrintStats( const char *pStatsFilename ) +{ + std::ofstream os( pStatsFilename, std::ios_base::out | std::ios_base::binary ); + + // user id + UUID userId; + QueryOrGenerateUserID( userId ); + unsigned char *userIdStr; + UuidToStringA( &userId, &userIdStr ); + os << userIdStr << "\n"; + RpcStringFree( &userIdStr ); + + // filename + int nOffset = g_URL.find_last_of( "/\\" ); + if ( nOffset == g_URL.npos ) + nOffset = 0; + std::string filename = g_URL.substr( nOffset + 1 ); + os << filename << '\n'; + + // number of events + int nEvents = g_events.size(); + os << nEvents << "\n"; + + // event data (tab-delimited) + for ( int i = 0; i < nEvents; ++i ) + { + os << GetEventName( g_events[ i ].event ) << "\t"; + os << g_events[ i ].time << "\t"; + os << int( 1000 * g_events[ i ].position ) << "\n"; + } +} + +void UploadStats() +{ + char pathname[ 256 ]; + if ( !GetRegistryString( "Software\\Valve\\Steam", "SteamExe", pathname, sizeof( pathname ) ) ) + return; + + char *pExeName = strrchr( pathname, '/' ); + if ( !pExeName ) + return; + + *pExeName = '\0'; // truncate exe filename to just pathname + + char filename[ 256 ]; + sprintf( filename, "%s/smpstats.txt", pathname ); + + PrintStats( filename ); + + ::ShellExecuteA( NULL, "open", "steam://smp/smpstats.txt", NULL, NULL, SW_SHOWNORMAL ); +} + +void RestoreRegistry() +{ + static bool s_bDone = false; + if ( s_bDone ) + return; + + s_bDone = true; + RestoreRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists ); +} + + +#ifdef USE_D3D8 + +void CleanupD3D() +{ + if ( g_pDrawVB ) + { + g_pDrawVB->Release(); + g_pDrawVB = NULL; + } + if ( g_pImg ) + { + g_pImg->Release(); + g_pImg = NULL; + } +#ifdef BLUR + if ( g_pBackBuf ) + { + g_pBackBuf->Release(); + g_pBackBuf = NULL; + } + if ( g_pBlurVB ) + { + g_pBlurVB->Release(); + g_pBlurVB = NULL; + } + if ( g_pTex ) + { + g_pTex->Release(); + g_pTex = NULL; + } + if ( g_pRT ) + { + g_pRT->Release(); + g_pRT = NULL; + } +#endif // BLUR + if ( g_pd3dDevice ) + { + g_pd3dDevice->Release(); + g_pd3dDevice = NULL; + } + if ( g_pD3D ) + { + g_pD3D->Release(); + g_pD3D = NULL; + } +} + +void InitTextureStageState( int nStage, DWORD dwColorOp, DWORD dwColorArg1, DWORD dwColorArg2, DWORD dwColorArg0 = D3DTA_CURRENT ) +{ + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLOROP, dwColorOp ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG1, dwColorArg1 ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG2, dwColorArg2 ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG0, dwColorArg0 ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); + g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); +} + +bool InitD3D( HWND hWnd, bool blur ) +{ + g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ); + if ( !g_pD3D ) + { + OutputDebugString( "Direct3DCreate8 FAILED!\n" ); + CleanupD3D(); + return false; + } + + D3DDISPLAYMODE d3ddm; + bool bFound = false; + int nAdapters = g_pD3D->GetAdapterCount(); + int nAdapterIndex = 0; + for ( ; nAdapterIndex < nAdapters; ++nAdapterIndex ) + { + if ( g_pD3D->GetAdapterMonitor( nAdapterIndex ) == g_hMonitor ) + { + if ( FAILED( g_pD3D->GetAdapterDisplayMode( nAdapterIndex, &d3ddm ) ) ) + { + OutputDebugString( "GetAdapterDisplayMode FAILED!\n" ); + CleanupD3D(); + return false; + } + + MONITORINFO mi; + mi.cbSize = sizeof( mi ); + GetMonitorInfo( g_hMonitor, &mi ); + bFound = true; + break; + } + } + if ( !bFound ) + { + OutputDebugString( "Starting monitor not found when creating D3D device!\n" ); + CleanupD3D(); + return false; + } + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory( &d3dpp, sizeof( d3dpp ) ); + d3dpp.BackBufferWidth = g_screenWidth; + d3dpp.BackBufferHeight = g_screenHeight; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = NULL; + d3dpp.Windowed = FALSE; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + if ( FAILED( g_pD3D->CreateDevice( nAdapterIndex, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) + { + OutputDebugString( "CreateDevice FAILED!\n" ); + CleanupD3D(); + return false; + } + + // create and fill vertex buffer(s) + float du = 0.5f / g_screenWidth; + float dv = 0.5f / g_screenHeight; + float u0 = du; + float u1 = 1.0f + du; + float v0 = dv; + float v1 = 1.0f + dv; + float drawverts[] = + { // x, y, z, u, v + -1, -1, 0, u0, v0, + -1, 1, 0, u0, v1, + 1, -1, 0, u1, v0, + 1, 1, 0, u1, v1, + }; + g_dwDrawFVF = D3DFVF_XYZ | D3DFVF_TEX1; + g_nDrawStride = sizeof( drawverts ) / 4; + + if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( drawverts ), D3DUSAGE_WRITEONLY, g_dwDrawFVF, D3DPOOL_MANAGED, &g_pDrawVB ) ) ) + { + OutputDebugString( "CreateVertexBuffer( g_pDrawVB ) FAILED!\n" ); + CleanupD3D(); + return false; + } + + BYTE* pDrawVBMem; + if ( FAILED( g_pDrawVB->Lock( 0, sizeof( drawverts ), &pDrawVBMem, 0 ) ) ) + { + OutputDebugString( "g_pDrawVB->Lock FAILED!\n" ); + CleanupD3D(); + return false; + } + memcpy( pDrawVBMem, drawverts, sizeof( drawverts ) ); + g_pDrawVB->Unlock(); + + g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride ); + g_pd3dDevice->SetVertexShader( g_dwDrawFVF ); +#ifdef BLUR + if ( blur ) + { + float f = 2.0f / ( 2.0f + sqrt( 2.0f ) ); + float ds = 2.0f * f / g_screenWidth; + float dt = 2.0f * f / g_screenHeight; + float s0 = ( 0.5f - f ) / g_screenWidth; + float s1 = 1.0f + s0; + float t0 = ( 0.5f - f ) / g_screenHeight; + float t1 = 1.0f + t0; + float blurverts[] = + { // x, y, z, u, v + -1, -1, 0, s0, t1, s0+ds, t1, s0, t1+dt, s0+ds, t1+dt, + -1, 1, 0, s0, t0, s0+ds, t0, s0, t0+dt, s0+ds, t0+dt, + 1, -1, 0, s1, t1, s1+ds, t1, s1, t1+dt, s1+ds, t1+dt, + 1, 1, 0, s1, t0, s1+ds, t0, s1, t0+dt, s1+ds, t0+dt, + }; + g_dwBlurFVF = D3DFVF_XYZ | D3DFVF_TEX4; + g_nBlurStride = sizeof( blurverts ) / 4; + + if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( blurverts ), D3DUSAGE_WRITEONLY, g_dwBlurFVF, D3DPOOL_MANAGED, &g_pBlurVB ) ) ) + { + OutputDebugString( "CreateVertexBuffer( g_pBlurVB ) FAILED!\n" ); + CleanupD3D(); + return false; + } + + BYTE* pBlurVBMem; + if ( FAILED( g_pBlurVB->Lock( 0, sizeof( blurverts ), &pBlurVBMem, 0 ) ) ) + { + OutputDebugString( "g_pBlurVB->Lock FAILED!\n" ); + CleanupD3D(); + return false; + } + memcpy( pBlurVBMem, blurverts, sizeof( blurverts ) ); + g_pBlurVB->Unlock(); + } +#endif // BLUR + + // create and fill texture + if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &g_pImg ) ) ) + { + OutputDebugString( "CreateTexture( g_pImg ) FAILED!\n" ); + CleanupD3D(); + return false; + } + + D3DLOCKED_RECT lockedRect; + if ( FAILED( g_pImg->LockRect( 0, &lockedRect, NULL, 0 ) ) ) + { + OutputDebugString( "g_pImg->LockRect FAILED!\n" ); + CleanupD3D(); + return false; + } + + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader ); + bitmapInfo.bmiHeader.biWidth = g_screenWidth; + bitmapInfo.bmiHeader.biHeight = g_screenHeight; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + if ( GetDIBits( g_hdcCapture, g_hbmCapture, 0, g_screenHeight, lockedRect.pBits, &bitmapInfo, DIB_RGB_COLORS ) != g_screenHeight ) + { + OutputDebugString( "GetDIBits FAILED to get the full image!\n" ); + } + + g_pImg->UnlockRect( 0 ); + +#ifdef BLUR + if ( blur ) + { + if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTex ) ) ) + { + OutputDebugString( "CreateTexture( g_pTex ) FAILED!\n" ); + CleanupD3D(); + return false; + } + + if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pRT ) ) ) + { + OutputDebugString( "CreateTexture( g_pRT ) FAILED!\n" ); + CleanupD3D(); + return false; + } + + IDirect3DSurface8 *pTexSurf = NULL; + g_pTex->GetSurfaceLevel( 0, &pTexSurf ); + IDirect3DSurface8 *pImgSurf = NULL; + g_pImg->GetSurfaceLevel( 0, &pImgSurf ); + + RECT rect = { 0, 0, g_screenWidth, g_screenHeight }; + POINT pt = { 0, 0 }; + g_pd3dDevice->CopyRects( pImgSurf, &rect, 1, pTexSurf, &pt ); + + pTexSurf->Release(); + pImgSurf->Release(); + } +#endif // BLUR + + g_pd3dDevice->SetTexture( 0, g_pImg ); + + InitTextureStageState( 0, D3DTOP_MODULATE, D3DTA_TEXTURE, D3DTA_TFACTOR ); +#ifdef BLUR + if ( blur ) + { + g_pd3dDevice->SetTexture( 0, g_pTex ); +// g_pd3dDevice->SetTexture( 1, g_pTex ); +// g_pd3dDevice->SetTexture( 2, g_pTex ); +// g_pd3dDevice->SetTexture( 3, g_pTex ); + + DWORD op = D3DTOP_DISABLE; // D3DTOP_MULTIPLYADD; + InitTextureStageState( 1, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT ); + InitTextureStageState( 2, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT ); + InitTextureStageState( 3, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT ); + } +#endif // BLUR + + return true; +} + +void DrawD3DFade( BYTE fade, bool blur ) +{ + if ( g_pd3dDevice ) + { +#ifdef BLUR + if ( g_pTex ) + { + if ( blur ) + { + IDirect3DSurface8 *pRTSurf = NULL; + g_pRT->GetSurfaceLevel( 0, &pRTSurf ); + g_pd3dDevice->SetRenderTarget( pRTSurf, NULL ); + + if ( g_pBackBuf ) + { + g_pBackBuf->Release(); + g_pBackBuf = NULL; + } + + g_pd3dDevice->BeginScene(); + + g_pd3dDevice->SetTexture( 0, g_pTex ); + g_pd3dDevice->SetTexture( 1, g_pTex ); + g_pd3dDevice->SetTexture( 2, g_pTex ); + g_pd3dDevice->SetTexture( 3, g_pTex ); + + g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD ); + g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD ); + g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD ); + + g_pd3dDevice->SetStreamSource( 0, g_pBlurVB, g_nBlurStride ); + g_pd3dDevice->SetVertexShader( g_dwBlurFVF ); + + DWORD quarter = 0x3f | ( 0x3f << 8 ) | ( 0x3f << 16 ) | ( 0x3f << 24 ); + g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, quarter ); + g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); + + g_pd3dDevice->EndScene(); + + pRTSurf->Release(); + + g_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackBuf ); + g_pd3dDevice->SetRenderTarget( g_pBackBuf, NULL ); + + IDirect3DTexture8 *pTemp = g_pTex; + g_pTex = g_pRT; + g_pRT = pTemp; + + g_pd3dDevice->SetTexture( 0, g_pTex ); + g_pd3dDevice->SetTexture( 1, NULL ); + g_pd3dDevice->SetTexture( 2, NULL ); + g_pd3dDevice->SetTexture( 3, NULL ); + + g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE ); + g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_DISABLE ); + + g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride ); + g_pd3dDevice->SetVertexShader( g_dwDrawFVF ); + } + } +#endif + + g_pd3dDevice->BeginScene(); + + // DWORD factor = 0xff | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 ); + DWORD factor = fade | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 ); + g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, factor ); + g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); + + g_pd3dDevice->EndScene(); + g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); + } +} + +#endif // USE_D3D8 + +int g_nTimingIndex = 0; +double g_timings[ 65536 ]; + +LRESULT CALLBACK WinProc( HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + switch ( msg ) + { + case WM_CREATE: + { + g_timeAtFadeStart = 0.0; + g_nBlurSteps = 0; + + g_hBlackFadingWindow = hWnd; + +#ifndef USE_D3D8 + MONITORINFO mi; + mi.cbSize = sizeof( mi ); + if ( GetMonitorInfo( g_hMonitor, &mi ) ) + { + SetWindowPos( hWnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, 0 ); + } +#endif + +#ifdef USE_D3D8 + InitD3D( hWnd, true ); +#endif // USE_D3D8 + if ( !g_bFadeIn ) + { + g_pFrame->ShowWindow( SW_HIDE ); + g_pFrame->PostMessage( WM_DESTROY, 0, 0 ); + } + + InvalidateRect( hWnd, NULL, TRUE ); + + SetTimer( hWnd, ID_SKIP_FADE_TIMER, 1000, NULL ); // if the fade doesn't start in 1 second, then just jump to the video + SetTimer( hWnd, ID_DRAW_TIMER, 10, NULL ); // draw timer + } + break; + +#ifdef USE_D3D8 + case WM_TIMER: // WM_ERASEBKGND: +#else + case WM_TIMER: // WM_ERASEBKGND: +// case WM_NCPAINT: +#endif + if ( wparam == ID_DRAW_TIMER ) + { + static LARGE_INTEGER s_nPerformanceFrequency; + if ( g_timeAtFadeStart == 0.0 ) + { + LARGE_INTEGER nTimeAtFadeStart; + QueryPerformanceCounter( &nTimeAtFadeStart ); + QueryPerformanceFrequency( &s_nPerformanceFrequency ); + g_timeAtFadeStart = nTimeAtFadeStart.QuadPart / double( s_nPerformanceFrequency.QuadPart ); + + KillTimer( hWnd, ID_SKIP_FADE_TIMER ); + SetTimer( hWnd, ID_SKIP_FADE_TIMER, 100 + UINT( FADE_TIME * 1000 ), NULL ); // restart skip fade timer and give it an extra 100ms to allow the fade to draw fully black once + } + + LARGE_INTEGER time; + QueryPerformanceCounter( &time ); + g_timings[ g_nTimingIndex++ ] = time.QuadPart / double( s_nPerformanceFrequency.QuadPart ); + float dt = ( float )( time.QuadPart / double( s_nPerformanceFrequency.QuadPart ) - g_timeAtFadeStart ); + + bool bFadeFinished = dt >= FADE_TIME; + float fraction = bFadeFinished ? 1.0f : dt / FADE_TIME; +/* + char str[ 256 ]; + sprintf( str, "A - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" ); + OutputDebugString( str ); +*/ + bool blur = g_bFadeIn && ( int( fraction * MAX_BLUR_STEPS ) > g_nBlurSteps ); + if ( blur ) + { + ++g_nBlurSteps; + } + + BYTE fade = BYTE( fraction * 255.999f ); + if ( g_bFadeIn ) + { + fade = 255 - fade; + } +/* + char str[ 256 ]; + sprintf( str, "fade = %d\n", fade ); + OutputDebugString( str ); +*/ +#ifdef USE_D3D8 + DrawD3DFade( fade, blur ); +#else // USE_D3D8 +// HDC hdc = GetDCEx( hWnd, ( HRGN )wparam, DCX_WINDOW | DCX_INTERSECTRGN ); + + if ( !PatBlt( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, BLACKNESS ) ) + { + OutputDebugString( "PatBlt FAILED!\n" ); + } + +// fade = 128; + BLENDFUNCTION blendfunc = { AC_SRC_OVER, 0, fade, 0 }; + if ( !::AlphaBlend( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, blendfunc ) ) + { + OutputDebugString( "AlphaBlend FAILED!\n" ); + } + + if ( !BitBlt( ( HDC )wparam, 0, 0, g_screenWidth, g_screenHeight, g_hdcBlend, 0, 0, SRCCOPY ) ) + { + OutputDebugString( "BitBlt FAILED!\n" ); + } + +// ReleaseDC( hWnd, hdc ); +// RedrawWindow( hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE ); +#endif // USE_D3D8 +/* +// char str[ 256 ]; + sprintf( str, "B - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" ); + OutputDebugString( str ); +*/ + if ( !bFadeFinished ) + break; + + // fall-through intentional +// OutputDebugString( "Fall-through from erase background\n" ); + } + +// case WM_TIMER: + { + if ( msg == WM_TIMER ) + { +/* + char str[ 256 ]; + sprintf( str, "Timer 0x%x triggered for window 0x%x\n", wparam, hWnd ); + OutputDebugString( str ); +*/ + if ( wparam == ID_DRAW_TIMER ) + { +// UpdateWindow( hWnd ); +// InvalidateRect( hWnd, NULL, TRUE ); +// break; + } + } + + KillTimer( hWnd, ID_SKIP_FADE_TIMER ); + KillTimer( hWnd, ID_DRAW_TIMER ); + + if ( !g_bFadeIn ) + { +// OutputDebugString( "closing fade window\n" ); + ShowWindow( hWnd, SW_HIDE ); + PostMessage( hWnd, WM_CLOSE, 0, 0 ); + return 1; + } + else if ( !g_bFrameCreated ) + { + g_bFrameCreated = true; +#ifdef USE_D3D8 +// OutputDebugString( "Cleanup D3D\n" ); + CleanupD3D(); +#endif + g_pFrame = &g_frame; + g_pFrame->GetWndClassInfo().m_wc.hIcon = LoadIcon( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDI_ICON ) ); + RECT rcPos = { CW_USEDEFAULT, 0, 0, 0 }; + +// OutputDebugString( "Create WMP frame\n" ); + + if ( g_osVersion < OSV_XP ) + { + g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW, 0, ( UINT )0 ); + } + else + { + g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, ( UINT )0 ); + + g_pFrame->ShowWindow( SW_SHOW ); + } + +// OutputDebugString( "Create WMP frame - done\n" ); + } + + // close WMP window once we paint the fullscreen fade window + if ( !g_bFadeIn ) + { + g_pFrame->ShowWindow( SW_HIDE ); + } + } + return 1; + + case WM_KEYDOWN: + if ( wparam == VK_ESCAPE ) + { + ::DestroyWindow( hWnd ); + } + break; + + case WM_DESTROY: + g_hBlackFadingWindow = NULL; + +#ifdef USE_D3D8 + CleanupD3D(); +#endif + + if ( g_bFrameCreated ) + { + g_bFrameCreated = false; + + g_pFrame->DestroyWindow(); + g_pFrame = NULL; + } + + ::PostQuitMessage( 0 ); + break; + } + + return DefWindowProc( hWnd, msg, wparam, lparam ); +} + +bool ShowFadeWindow( bool bShow ) +{ + if ( bShow ) + { + g_timeAtFadeStart = 0.0; + g_bFadeIn = false; + + SetTimer( g_hBlackFadingWindow, ID_DRAW_TIMER, 10, NULL ); + + if ( g_pFrame ) + { + g_pFrame->ShowWindow( SW_HIDE ); + } +#ifdef USE_D3D8 + if ( g_osVersion < OSV_XP ) + { + ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW ); + } + InitD3D( g_hBlackFadingWindow, false ); +#else // USE_D3D8 + ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW ); +// ::ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED ); +#endif // USE_D3D8 + InvalidateRect( g_hBlackFadingWindow, NULL, TRUE ); + } + else + { + if ( g_osVersion < OSV_XP ) + { +// OutputDebugString( "hiding fade window\n" ); + ShowWindow( g_hBlackFadingWindow, SW_HIDE ); + } + else + { +// OutputDebugString( "Deferring erase on fade window\n" ); + ::SetWindowPos( g_hBlackFadingWindow, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_DEFERERASE ); + } + } + return true; +} + +HWND CreateFullscreenWindow( bool bFadeIn ) +{ + if ( g_hBlackFadingWindow ) + return g_hBlackFadingWindow; + + static s_bRegistered = false; + if ( !s_bRegistered ) + { + WNDCLASS wc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = ( WNDPROC )WinProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_hInstance; + wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "myclass"; + + if ( !RegisterClass( &wc ) ) + return 0; + + s_bRegistered = true; + } + + g_bFadeIn = bFadeIn; + DWORD windowStyle = WS_POPUP; +#ifndef USE_D3D8 + windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE; +#endif + if ( g_osVersion < OSV_XP ) + { + windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE; + } + + MONITORINFO mi; + mi.cbSize = sizeof( mi ); + if ( !GetMonitorInfo( g_hMonitor, &mi ) ) + { + GetClientRect( GetDesktopWindow(), &mi.rcMonitor ); + } + + g_hBlackFadingWindow = CreateWindow( "myclass", _T( "Steam Media Player" ), windowStyle, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, NULL, NULL, g_hInstance, NULL ); +#ifndef USE_D3D8 + ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED ); +#endif + if ( g_osVersion < OSV_XP ) + { + ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED ); + } + + while ( ShowCursor( FALSE ) >= 0 ) + ; + + return g_hBlackFadingWindow; +} + +bool CreateDesktopBitmaps() +{ + MONITORINFOEX mi; + mi.cbSize = sizeof( mi ); + if ( !GetMonitorInfo( g_hMonitor, &mi ) ) + return false; + + g_screenWidth = mi.rcMonitor.right - mi.rcMonitor.left; + g_screenHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; + + HDC hdcScreen = CreateDC( mi.szDevice, mi.szDevice, NULL, NULL ); + if ( !hdcScreen ) + return false; + + g_hdcCapture = CreateCompatibleDC( hdcScreen ); + g_hdcBlend = CreateCompatibleDC( hdcScreen ); + if ( !g_hdcCapture || !g_hdcBlend ) + return false; + + if ( ( GetDeviceCaps( hdcScreen, SHADEBLENDCAPS ) & SB_CONST_ALPHA ) == 0 ) + { + OutputDebugString( "display doesn't support AlphaBlend!\n" ); + } + + if ( ( GetDeviceCaps( hdcScreen, RASTERCAPS ) & RC_BITBLT ) == 0 ) + { + OutputDebugString( "display doesn't support BitBlt!\n" ); + } + + if ( GetDeviceCaps( hdcScreen, BITSPIXEL ) < 32 ) + { + OutputDebugString( "display doesn't support 32bpp!\n" ); + } + + if ( g_screenWidth != GetDeviceCaps( hdcScreen, HORZRES ) || + g_screenHeight != GetDeviceCaps( hdcScreen, VERTRES ) ) + { + OutputDebugString( "Screen DC size differs from monitor size!\n" ); + } + + g_hbmCapture = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight ); + g_hbmBlend = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight ); + if ( !g_hbmCapture || !g_hbmBlend ) + return false; + + HGDIOBJ oldCaptureObject = SelectObject( g_hdcCapture, g_hbmCapture ); + HGDIOBJ oldBlendObject = SelectObject( g_hdcBlend, g_hbmBlend ); + + if ( !BitBlt( g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, hdcScreen, 0, 0, SRCCOPY ) ) + return false; + + SelectObject( g_hdcCapture, oldCaptureObject ); + SelectObject( g_hdcBlend, oldBlendObject ); + + return true; +} + +void PrintLastError( const char *pPrefix ) +{ +#ifdef _DEBUG + DWORD dw = GetLastError(); + + LPVOID lpMsgBuf; + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dw, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), + ( LPTSTR )&lpMsgBuf, 0, NULL ); + + OutputDebugString( pPrefix ); + char msg[ 256 ]; + sprintf( msg, "(%d) ", dw ); + OutputDebugString( msg ); + OutputDebugString( ( char * )lpMsgBuf ); + + LocalFree( lpMsgBuf ); +#endif +} + +void KillOtherSMPs() +{ + DWORD nBytesReturned = 0; + DWORD procIds[ 1024 ]; + if ( !EnumProcesses( procIds, sizeof( procIds ), &nBytesReturned ) ) + { + PrintLastError( "EnumProcesses Error: " ); + return; + } + + DWORD dwCurrentProcessId = GetCurrentProcessId(); + + int nProcIds = nBytesReturned / sizeof( DWORD ); + for ( int i = 0; i < nProcIds; ++i ) + { + if ( procIds[ i ] == dwCurrentProcessId ) + continue; + + if ( procIds[ i ] == 0 ) // system idle process + continue; + + HANDLE hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, procIds[ i ] ); + if ( !hProcess ) + { + PrintLastError( "OpenProcess Error: " ); + continue; + } + + HMODULE hMod[ 1 ]; + DWORD cbNeeded; + if ( !EnumProcessModules( hProcess, hMod, sizeof( hMod ), &cbNeeded ) ) + { + PrintLastError( "EnumProcessModules Error: " ); + continue; + } + + char processName[ 1024 ]; + int nChars = GetModuleBaseName( hProcess, hMod[ 0 ], processName, sizeof( processName ) / sizeof( char ) ); + if ( nChars >= sizeof( processName ) ) + { + PrintLastError( "GetModuleBaseName Error: " ); + continue; + } + + if ( strcmp( processName, "smp.exe" ) == 0 ) + { + OutputDebugString( "!!! Killing smp.exe !!!\n" ); + TerminateProcess( hProcess, 0 ); + } + + if ( !CloseHandle( hProcess ) ) + { + PrintLastError( "CloseHandle Error: " ); + continue; + } + } +} + +void ParseCommandLine( const char *cmdline, std::vector< std::string > ¶ms ) +{ + params.push_back( "" ); + + bool quoted = false; + for ( const char *cp = cmdline; *cp; ++cp ) + { + if ( *cp == '\"' ) + { + quoted = !quoted; + } + else if ( isspace( *cp ) && !quoted ) + { + if ( !params.back().empty() ) + { + params.push_back( "" ); + } + } + else + { + params.back().push_back( *cp ); + } + } + + if ( params.back().empty() ) + { + params.pop_back(); + } +} + +///////////////////////////////////////////////////////////////////////////// +// +extern "C" int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/ ) +{ + g_hInstance = hInstance; + + KillOtherSMPs(); + + g_lpCommandLine = lpCmdLine; + if ( lpCmdLine == NULL || *lpCmdLine == '\0' ) + return 0; + + std::vector< std::string > params; + ParseCommandLine( lpCmdLine, params ); + int nParams = params.size(); + for ( int i = 0; i < nParams; ++i ) + { + if ( params[ i ][ 0 ] == '-' || params[ i ][ 0 ] == '/' ) + { + const char *pOption = params[ i ].c_str() + 1; + if ( strcmp( pOption, "reportstats" ) == 0 ) + { + g_bReportStats = true; + } + else if ( strcmp( pOption, "localsteamserver" ) == 0 ) + { + g_bUseLocalSteamServer = true; + } + else if ( strcmp( pOption, "redirect" ) == 0 ) + { + ++i; + g_redirectTarget = params[ i ]; + } + } + else + { + g_URL = params[ i ]; + } + } + + SetRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", 0, g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists ); + atexit( RestoreRegistry ); + + LogPlayerEvent( ET_APPLAUNCH, 0.0f ); + + lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT + + CoInitialize( 0 ); + _Module.Init( ObjectMap, hInstance, &LIBID_ATLLib ); + + ::InitCommonControls(); + + POINT pt; + GetCursorPos( &pt ); + g_hMonitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST ); + + if ( !CreateDesktopBitmaps() ) + { + OutputDebugString( "CreateDesktopBitmaps FAILED!\n" ); + } + + ShowCursor( FALSE ); + CreateFullscreenWindow( true ); + + MSG msg; + while ( GetMessage( &msg, 0, 0, 0 ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + LogPlayerEvent( ET_APPEXIT ); + if ( g_bReportStats ) + { + UploadStats(); + } + + if ( !g_redirectTarget.empty() ) + { + ::ShellExecuteA( NULL, "open", g_redirectTarget.c_str(), NULL, NULL, SW_SHOWNORMAL ); + } + + _Module.Term(); + CoUninitialize(); + + RestoreRegistry(); + + return 0; +} |