Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1441 lines
36 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // smp.cpp : Main window procedure
  3. //
  4. #include "stdafx.h"
  5. #include "resource.h"
  6. #include "initguid.h"
  7. #include "CWMPHost.h"
  8. #include <commctrl.h>
  9. #include <windows.h>
  10. #include <psapi.h>
  11. #include <math.h>
  12. #include <cstdio>
  13. #include <vector>
  14. #include <string>
  15. #include <strstream>
  16. #include <fstream>
  17. #include "IceKey.h"
  18. CComModule _Module;
  19. BEGIN_OBJECT_MAP(ObjectMap)
  20. END_OBJECT_MAP()
  21. #define ID_SKIP_FADE_TIMER 1
  22. #define ID_DRAW_TIMER 2
  23. const float FADE_TIME = 1.0f;
  24. const int MAX_BLUR_STEPS = 100;
  25. HINSTANCE g_hInstance;
  26. HWND g_hBlackFadingWindow = 0;
  27. bool g_bFadeIn = true;
  28. bool g_bFrameCreated = false;
  29. CWMPHost g_frame;
  30. CWMPHost *g_pFrame = NULL;
  31. HDC g_hdcCapture = 0;
  32. HDC g_hdcBlend = 0;
  33. HBITMAP g_hbmCapture = 0;
  34. HBITMAP g_hbmBlend = 0;
  35. HMONITOR g_hMonitor = 0;
  36. int g_screenWidth = 0;
  37. int g_screenHeight = 0;
  38. LPTSTR g_lpCommandLine = NULL;
  39. std::string g_redirectTarget;
  40. std::string g_URL;
  41. bool g_bReportStats = false;
  42. bool g_bUseLocalSteamServer = false;
  43. double g_timeAtFadeStart = 0.0;
  44. int g_nBlurSteps = 0;
  45. void LogPlayerEvent( EventType_t e );
  46. enum OSVersion
  47. {
  48. OSV_95,
  49. OSV_95OSR2,
  50. OSV_98,
  51. OSV_98SE,
  52. OSV_ME,
  53. OSV_NT4,
  54. OSV_2000,
  55. OSV_SERVER2003,
  56. OSV_XP,
  57. OSV_XPSP1,
  58. OSV_XPSP2,
  59. OSV_XPSP3,
  60. OSV_VISTA,
  61. OSV_UNKNOWN,
  62. };
  63. OSVersion DetectOSVersion()
  64. {
  65. OSVERSIONINFO version;
  66. version.dwOSVersionInfoSize = sizeof( version );
  67. GetVersionEx( &version );
  68. if ( version.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS )
  69. {
  70. if ( version.dwMajorVersion != 4 )
  71. return OSV_UNKNOWN;
  72. switch ( version.dwMinorVersion )
  73. {
  74. case 0:
  75. return strstr( version.szCSDVersion, _TEXT( " C" ) ) == version.szCSDVersion ? OSV_95OSR2 : OSV_95;
  76. case 10:
  77. return ( strstr( version.szCSDVersion, _TEXT( " A" ) ) == version.szCSDVersion ) || ( strstr( version.szCSDVersion, _TEXT( " B" ) ) == version.szCSDVersion ) ? OSV_98SE : OSV_98;
  78. case 90:
  79. return OSV_ME;
  80. }
  81. }
  82. else if ( version.dwPlatformId & VER_PLATFORM_WIN32_NT )
  83. {
  84. if ( version.dwMajorVersion == 4 )
  85. return OSV_NT4; // or mabye NT3.5???
  86. if ( version.dwMajorVersion == 6 )
  87. return OSV_VISTA;
  88. if ( version.dwMajorVersion != 5 )
  89. return OSV_UNKNOWN;
  90. switch ( version.dwMinorVersion )
  91. {
  92. case 0:
  93. return OSV_2000;
  94. case 1:
  95. {
  96. if ( version.szCSDVersion == NULL )
  97. return OSV_XP;
  98. if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 1" ) ) != NULL )
  99. return OSV_XPSP1;
  100. if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 2" ) ) != NULL )
  101. return OSV_XPSP2;
  102. if ( strstr( version.szCSDVersion, _TEXT( "Service Pack 3" ) ) != NULL )
  103. return OSV_XPSP3;
  104. }
  105. case 2:
  106. return OSV_SERVER2003; // or maybe XP64???
  107. }
  108. }
  109. return OSV_UNKNOWN;
  110. }
  111. const OSVersion g_osVersion = DetectOSVersion();
  112. #define BLUR
  113. #define USE_D3D8
  114. #ifdef USE_D3D8
  115. #include <d3d8.h>
  116. IDirect3D8* g_pD3D = NULL;
  117. IDirect3DDevice8* g_pd3dDevice = NULL;
  118. IDirect3DVertexBuffer8* g_pDrawVB = NULL;
  119. IDirect3DTexture8* g_pImg = NULL;
  120. int g_nDrawStride = 0;
  121. DWORD g_dwDrawFVF = 0;
  122. #ifdef BLUR
  123. int g_nBlurStride = 0;
  124. DWORD g_dwBlurFVF = 0;
  125. IDirect3DVertexBuffer8* g_pBlurVB = NULL;
  126. IDirect3DTexture8* g_pTex = NULL;
  127. IDirect3DTexture8* g_pRT = NULL;
  128. IDirect3DSurface8* g_pBackBuf = NULL;
  129. #endif // BLUR
  130. #endif // USE_D3D8
  131. DWORD g_dwUseVMROverlayOldValue = 0;
  132. bool g_bUseVMROverlayValueExists = false;
  133. void SetRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwValue, DWORD &dwOldValue, bool &bValueExisted )
  134. {
  135. HKEY hKey = 0;
  136. LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
  137. if ( rval != ERROR_SUCCESS )
  138. {
  139. OutputDebugString( "unable to open registry key: " );
  140. OutputDebugString( pKeyName );
  141. OutputDebugString( "\n" );
  142. return;
  143. }
  144. DWORD dwType = 0;
  145. DWORD dwSize = sizeof( dwOldValue );
  146. // amusingly enough, if pValueName doesn't exist, RegQueryValueEx returns ERROR_FILE_NOT_FOUND
  147. rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )&dwOldValue, &dwSize );
  148. bValueExisted = ( rval == ERROR_SUCCESS );
  149. rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwValue, sizeof( dwValue ) );
  150. if ( rval != ERROR_SUCCESS )
  151. {
  152. OutputDebugString( "unable to write registry value " );
  153. OutputDebugString( pValueName );
  154. OutputDebugString( " in key " );
  155. OutputDebugString( pKeyName );
  156. OutputDebugString( "\n" );
  157. }
  158. RegCloseKey( hKey );
  159. }
  160. void RestoreRegistryValue( const char *pKeyName, const char *pValueName, DWORD dwOldValue, bool bValueExisted )
  161. {
  162. HKEY hKey = 0;
  163. LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
  164. if ( rval != ERROR_SUCCESS )
  165. {
  166. OutputDebugString( "unable to open registry key: " );
  167. OutputDebugString( pKeyName );
  168. OutputDebugString( "\n" );
  169. return;
  170. }
  171. if ( bValueExisted )
  172. {
  173. rval = RegSetValueEx( hKey, pValueName, 0, REG_DWORD, ( CONST BYTE* )&dwOldValue, sizeof( dwOldValue ) );
  174. }
  175. else
  176. {
  177. rval = RegDeleteValue( hKey, pValueName );
  178. }
  179. if ( rval != ERROR_SUCCESS )
  180. {
  181. OutputDebugString( "SetRegistryValue FAILED!\n" );
  182. }
  183. RegCloseKey( hKey );
  184. }
  185. bool GetRegistryString( const char *pKeyName, const char *pValueName, const char *pValueString, int nValueLen )
  186. {
  187. HKEY hKey = 0;
  188. LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, pKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
  189. if ( rval != ERROR_SUCCESS )
  190. {
  191. OutputDebugString( "unable to open registry key: " );
  192. OutputDebugString( pKeyName );
  193. OutputDebugString( "\n" );
  194. return false;
  195. }
  196. DWORD dwType = 0;
  197. rval = RegQueryValueEx( hKey, pValueName, NULL, &dwType, ( LPBYTE )pValueString, ( DWORD* )&nValueLen );
  198. RegCloseKey( hKey );
  199. if ( rval != ERROR_SUCCESS || dwType != REG_SZ )
  200. {
  201. OutputDebugString( "unable to read registry string: " );
  202. OutputDebugString( pValueName );
  203. OutputDebugString( "\n" );
  204. return false;
  205. }
  206. return true;
  207. }
  208. struct EventData_t
  209. {
  210. EventData_t( int t, float pos, EventType_t e )
  211. : time( t ), position( pos ), event( e )
  212. {
  213. }
  214. int time; // real time
  215. float position; // movie position
  216. EventType_t event; // event type
  217. };
  218. const char *GetEventName( EventType_t event )
  219. {
  220. switch ( event )
  221. {
  222. case ET_APPLAUNCH: return "al";
  223. case ET_APPEXIT: return "ae";
  224. case ET_CLOSE: return "cl";
  225. case ET_FADEOUT: return "fo";
  226. case ET_MEDIABEGIN: return "mb";
  227. case ET_MEDIAEND: return "me";
  228. case ET_JUMPHOME: return "jh";
  229. case ET_JUMPEND: return "je";
  230. case ET_PLAY: return "pl";
  231. case ET_PAUSE: return "ps";
  232. case ET_STOP: return "st";
  233. case ET_SCRUBFROM: return "jf";
  234. case ET_SCRUBTO: return "jt";
  235. case ET_STEPFWD: return "sf";
  236. case ET_STEPBCK: return "sb";
  237. case ET_JUMPFWD: return "jf";
  238. case ET_JUMPBCK: return "jb";
  239. case ET_REPEAT: return "rp";
  240. case ET_MAXIMIZE: return "mx";
  241. case ET_MINIMIZE: return "mn";
  242. case ET_RESTORE: return "rs";
  243. default: return "<unknown>";
  244. }
  245. }
  246. std::vector< EventData_t > g_events;
  247. void LogPlayerEvent( EventType_t e, float pos )
  248. {
  249. if ( !g_bReportStats )
  250. return;
  251. static int s_firstTick = GetTickCount();
  252. int time = GetTickCount() - s_firstTick;
  253. #if 0
  254. char msg[ 256 ];
  255. sprintf( msg, "event %s at time %d and pos %d\n", GetEventName( e ), time, int( 1000 * pos ) );
  256. OutputDebugString( msg );
  257. #endif
  258. bool bDropEvent = false;
  259. int nEvents = g_events.size();
  260. if ( ( e == ET_STEPFWD || e == ET_STEPBCK ) && nEvents >= 2 )
  261. {
  262. const EventData_t &e1 = g_events[ nEvents - 1 ];
  263. const EventData_t &e2 = g_events[ nEvents - 2 ];
  264. if ( ( e1.event == e || e1.event == ET_REPEAT ) && e2.event == e )
  265. {
  266. // only store starting and ending stepfwd or stepbck events, since there can be so many
  267. // also keep events that are more than a second apart
  268. if ( e1.event == ET_REPEAT )
  269. {
  270. // keep dropping events while e1 isn't before a gap
  271. bDropEvent = time - e1.time < 1000;
  272. }
  273. else
  274. {
  275. // e2 was kept last time, so keep e1 if e2 was kept because it was before a gap
  276. bDropEvent = e1.time - e2.time < 1000;
  277. }
  278. }
  279. }
  280. if ( bDropEvent )
  281. {
  282. g_events[ nEvents - 1 ] = EventData_t( time, pos, ET_REPEAT );
  283. }
  284. else
  285. {
  286. g_events.push_back( EventData_t( time, pos, e ) );
  287. }
  288. }
  289. char C2M_UPLOADDATA = 'q';
  290. char C2M_UPLOADDATA_PROTOCOL_VERSION = 1;
  291. char C2M_UPLOADDATA_DATA_VERSION = 1;
  292. inline void WriteHexDigit( std::ostream &os, byte src )
  293. {
  294. os.put( ( src <= 9 ) ? src + '0' : src - 10 + 'A' );
  295. }
  296. inline void WriteByte( std::ostream &os, byte src )
  297. {
  298. WriteHexDigit( os, src >> 4 );
  299. WriteHexDigit( os, src & 0xf );
  300. }
  301. inline void WriteShort( std::ostream &os, unsigned short src )
  302. {
  303. WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
  304. WriteByte( os, ( byte )( src & 0xff ) );
  305. }
  306. inline void WriteInt24( std::ostream &os, int src )
  307. {
  308. WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) );
  309. WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
  310. WriteByte( os, ( byte )( src & 0xff ) );
  311. }
  312. inline void WriteInt( std::ostream &os, int src )
  313. {
  314. WriteByte( os, ( byte )( ( src >> 24 ) & 0xff ) );
  315. WriteByte( os, ( byte )( ( src >> 16 ) & 0xff ) );
  316. WriteByte( os, ( byte )( ( src >> 8 ) & 0xff ) );
  317. WriteByte( os, ( byte )( src & 0xff ) );
  318. }
  319. inline void WriteFloat( std::ostream &os, float src )
  320. {
  321. WriteInt( os, *( int* )&src );
  322. }
  323. void WriteUUID( std::ostream &os, const UUID &uuid )
  324. {
  325. WriteInt( os, uuid.Data1 );
  326. WriteShort( os, uuid.Data2 );
  327. WriteShort( os, uuid.Data3 );
  328. for ( int i = 0; i < 8; ++i )
  329. {
  330. WriteByte( os, uuid.Data4[ i ] );
  331. }
  332. }
  333. bool QueryOrGenerateUserID( UUID &userId )
  334. {
  335. HKEY hKey = 0;
  336. LONG rval = RegCreateKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Steam", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
  337. if ( rval != ERROR_SUCCESS )
  338. {
  339. UuidCreate( &userId );
  340. return false;
  341. }
  342. DWORD dwType = 0;
  343. unsigned char idstr[ 40 ];
  344. DWORD dwSize = sizeof( idstr );
  345. rval = RegQueryValueEx( hKey, "smpid", NULL, &dwType, ( LPBYTE )idstr, &dwSize );
  346. if ( rval != ERROR_SUCCESS || dwType != REG_SZ )
  347. {
  348. UuidCreate( &userId );
  349. unsigned char *outstring = NULL;
  350. UuidToString( &userId, &outstring );
  351. if ( outstring == NULL || *outstring == '\0' )
  352. {
  353. RegCloseKey( hKey );
  354. return false;
  355. }
  356. rval = RegSetValueEx( hKey, "smpid", 0, REG_SZ, ( CONST BYTE* )outstring, sizeof( idstr ) );
  357. RpcStringFree( &outstring );
  358. RegCloseKey( hKey );
  359. return rval == ERROR_SUCCESS;
  360. }
  361. if ( RPC_S_OK != UuidFromString( idstr, &userId ) )
  362. return false;
  363. RegCloseKey( hKey );
  364. return true;
  365. }
  366. void PrintStats( const char *pStatsFilename )
  367. {
  368. std::ofstream os( pStatsFilename, std::ios_base::out | std::ios_base::binary );
  369. // user id
  370. UUID userId;
  371. QueryOrGenerateUserID( userId );
  372. unsigned char *userIdStr;
  373. UuidToStringA( &userId, &userIdStr );
  374. os << userIdStr << "\n";
  375. RpcStringFree( &userIdStr );
  376. // filename
  377. int nOffset = g_URL.find_last_of( "/\\" );
  378. if ( nOffset == g_URL.npos )
  379. nOffset = 0;
  380. std::string filename = g_URL.substr( nOffset + 1 );
  381. os << filename << '\n';
  382. // number of events
  383. int nEvents = g_events.size();
  384. os << nEvents << "\n";
  385. // event data (tab-delimited)
  386. for ( int i = 0; i < nEvents; ++i )
  387. {
  388. os << GetEventName( g_events[ i ].event ) << "\t";
  389. os << g_events[ i ].time << "\t";
  390. os << int( 1000 * g_events[ i ].position ) << "\n";
  391. }
  392. }
  393. void UploadStats()
  394. {
  395. char pathname[ 256 ];
  396. if ( !GetRegistryString( "Software\\Valve\\Steam", "SteamExe", pathname, sizeof( pathname ) ) )
  397. return;
  398. char *pExeName = strrchr( pathname, '/' );
  399. if ( !pExeName )
  400. return;
  401. *pExeName = '\0'; // truncate exe filename to just pathname
  402. char filename[ 256 ];
  403. sprintf( filename, "%s/smpstats.txt", pathname );
  404. PrintStats( filename );
  405. ::ShellExecuteA( NULL, "open", "steam://smp/smpstats.txt", NULL, NULL, SW_SHOWNORMAL );
  406. }
  407. void RestoreRegistry()
  408. {
  409. static bool s_bDone = false;
  410. if ( s_bDone )
  411. return;
  412. s_bDone = true;
  413. RestoreRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists );
  414. }
  415. #ifdef USE_D3D8
  416. void CleanupD3D()
  417. {
  418. if ( g_pDrawVB )
  419. {
  420. g_pDrawVB->Release();
  421. g_pDrawVB = NULL;
  422. }
  423. if ( g_pImg )
  424. {
  425. g_pImg->Release();
  426. g_pImg = NULL;
  427. }
  428. #ifdef BLUR
  429. if ( g_pBackBuf )
  430. {
  431. g_pBackBuf->Release();
  432. g_pBackBuf = NULL;
  433. }
  434. if ( g_pBlurVB )
  435. {
  436. g_pBlurVB->Release();
  437. g_pBlurVB = NULL;
  438. }
  439. if ( g_pTex )
  440. {
  441. g_pTex->Release();
  442. g_pTex = NULL;
  443. }
  444. if ( g_pRT )
  445. {
  446. g_pRT->Release();
  447. g_pRT = NULL;
  448. }
  449. #endif // BLUR
  450. if ( g_pd3dDevice )
  451. {
  452. g_pd3dDevice->Release();
  453. g_pd3dDevice = NULL;
  454. }
  455. if ( g_pD3D )
  456. {
  457. g_pD3D->Release();
  458. g_pD3D = NULL;
  459. }
  460. }
  461. void InitTextureStageState( int nStage, DWORD dwColorOp, DWORD dwColorArg1, DWORD dwColorArg2, DWORD dwColorArg0 = D3DTA_CURRENT )
  462. {
  463. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLOROP, dwColorOp );
  464. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG1, dwColorArg1 );
  465. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG2, dwColorArg2 );
  466. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_COLORARG0, dwColorArg0 );
  467. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  468. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
  469. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
  470. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  471. g_pd3dDevice->SetTextureStageState( nStage, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  472. }
  473. bool InitD3D( HWND hWnd, bool blur )
  474. {
  475. g_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
  476. if ( !g_pD3D )
  477. {
  478. OutputDebugString( "Direct3DCreate8 FAILED!\n" );
  479. CleanupD3D();
  480. return false;
  481. }
  482. D3DDISPLAYMODE d3ddm;
  483. bool bFound = false;
  484. int nAdapters = g_pD3D->GetAdapterCount();
  485. int nAdapterIndex = 0;
  486. for ( ; nAdapterIndex < nAdapters; ++nAdapterIndex )
  487. {
  488. if ( g_pD3D->GetAdapterMonitor( nAdapterIndex ) == g_hMonitor )
  489. {
  490. if ( FAILED( g_pD3D->GetAdapterDisplayMode( nAdapterIndex, &d3ddm ) ) )
  491. {
  492. OutputDebugString( "GetAdapterDisplayMode FAILED!\n" );
  493. CleanupD3D();
  494. return false;
  495. }
  496. MONITORINFO mi;
  497. mi.cbSize = sizeof( mi );
  498. GetMonitorInfo( g_hMonitor, &mi );
  499. bFound = true;
  500. break;
  501. }
  502. }
  503. if ( !bFound )
  504. {
  505. OutputDebugString( "Starting monitor not found when creating D3D device!\n" );
  506. CleanupD3D();
  507. return false;
  508. }
  509. D3DPRESENT_PARAMETERS d3dpp;
  510. ZeroMemory( &d3dpp, sizeof( d3dpp ) );
  511. d3dpp.BackBufferWidth = g_screenWidth;
  512. d3dpp.BackBufferHeight = g_screenHeight;
  513. d3dpp.BackBufferFormat = d3ddm.Format;
  514. d3dpp.BackBufferCount = 1;
  515. d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  516. d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  517. d3dpp.hDeviceWindow = NULL;
  518. d3dpp.Windowed = FALSE;
  519. d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  520. d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  521. if ( FAILED( g_pD3D->CreateDevice( nAdapterIndex, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) )
  522. {
  523. OutputDebugString( "CreateDevice FAILED!\n" );
  524. CleanupD3D();
  525. return false;
  526. }
  527. // create and fill vertex buffer(s)
  528. float du = 0.5f / g_screenWidth;
  529. float dv = 0.5f / g_screenHeight;
  530. float u0 = du;
  531. float u1 = 1.0f + du;
  532. float v0 = dv;
  533. float v1 = 1.0f + dv;
  534. float drawverts[] =
  535. { // x, y, z, u, v
  536. -1, -1, 0, u0, v0,
  537. -1, 1, 0, u0, v1,
  538. 1, -1, 0, u1, v0,
  539. 1, 1, 0, u1, v1,
  540. };
  541. g_dwDrawFVF = D3DFVF_XYZ | D3DFVF_TEX1;
  542. g_nDrawStride = sizeof( drawverts ) / 4;
  543. if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( drawverts ), D3DUSAGE_WRITEONLY, g_dwDrawFVF, D3DPOOL_MANAGED, &g_pDrawVB ) ) )
  544. {
  545. OutputDebugString( "CreateVertexBuffer( g_pDrawVB ) FAILED!\n" );
  546. CleanupD3D();
  547. return false;
  548. }
  549. BYTE* pDrawVBMem;
  550. if ( FAILED( g_pDrawVB->Lock( 0, sizeof( drawverts ), &pDrawVBMem, 0 ) ) )
  551. {
  552. OutputDebugString( "g_pDrawVB->Lock FAILED!\n" );
  553. CleanupD3D();
  554. return false;
  555. }
  556. memcpy( pDrawVBMem, drawverts, sizeof( drawverts ) );
  557. g_pDrawVB->Unlock();
  558. g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride );
  559. g_pd3dDevice->SetVertexShader( g_dwDrawFVF );
  560. #ifdef BLUR
  561. if ( blur )
  562. {
  563. float f = 2.0f / ( 2.0f + sqrt( 2.0f ) );
  564. float ds = 2.0f * f / g_screenWidth;
  565. float dt = 2.0f * f / g_screenHeight;
  566. float s0 = ( 0.5f - f ) / g_screenWidth;
  567. float s1 = 1.0f + s0;
  568. float t0 = ( 0.5f - f ) / g_screenHeight;
  569. float t1 = 1.0f + t0;
  570. float blurverts[] =
  571. { // x, y, z, u, v
  572. -1, -1, 0, s0, t1, s0+ds, t1, s0, t1+dt, s0+ds, t1+dt,
  573. -1, 1, 0, s0, t0, s0+ds, t0, s0, t0+dt, s0+ds, t0+dt,
  574. 1, -1, 0, s1, t1, s1+ds, t1, s1, t1+dt, s1+ds, t1+dt,
  575. 1, 1, 0, s1, t0, s1+ds, t0, s1, t0+dt, s1+ds, t0+dt,
  576. };
  577. g_dwBlurFVF = D3DFVF_XYZ | D3DFVF_TEX4;
  578. g_nBlurStride = sizeof( blurverts ) / 4;
  579. if ( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof( blurverts ), D3DUSAGE_WRITEONLY, g_dwBlurFVF, D3DPOOL_MANAGED, &g_pBlurVB ) ) )
  580. {
  581. OutputDebugString( "CreateVertexBuffer( g_pBlurVB ) FAILED!\n" );
  582. CleanupD3D();
  583. return false;
  584. }
  585. BYTE* pBlurVBMem;
  586. if ( FAILED( g_pBlurVB->Lock( 0, sizeof( blurverts ), &pBlurVBMem, 0 ) ) )
  587. {
  588. OutputDebugString( "g_pBlurVB->Lock FAILED!\n" );
  589. CleanupD3D();
  590. return false;
  591. }
  592. memcpy( pBlurVBMem, blurverts, sizeof( blurverts ) );
  593. g_pBlurVB->Unlock();
  594. }
  595. #endif // BLUR
  596. // create and fill texture
  597. if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &g_pImg ) ) )
  598. {
  599. OutputDebugString( "CreateTexture( g_pImg ) FAILED!\n" );
  600. CleanupD3D();
  601. return false;
  602. }
  603. D3DLOCKED_RECT lockedRect;
  604. if ( FAILED( g_pImg->LockRect( 0, &lockedRect, NULL, 0 ) ) )
  605. {
  606. OutputDebugString( "g_pImg->LockRect FAILED!\n" );
  607. CleanupD3D();
  608. return false;
  609. }
  610. BITMAPINFO bitmapInfo;
  611. bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader );
  612. bitmapInfo.bmiHeader.biWidth = g_screenWidth;
  613. bitmapInfo.bmiHeader.biHeight = g_screenHeight;
  614. bitmapInfo.bmiHeader.biPlanes = 1;
  615. bitmapInfo.bmiHeader.biBitCount = 32;
  616. bitmapInfo.bmiHeader.biCompression = BI_RGB;
  617. bitmapInfo.bmiHeader.biSizeImage = 0;
  618. bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  619. bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  620. bitmapInfo.bmiHeader.biClrUsed = 0;
  621. bitmapInfo.bmiHeader.biClrImportant = 0;
  622. if ( GetDIBits( g_hdcCapture, g_hbmCapture, 0, g_screenHeight, lockedRect.pBits, &bitmapInfo, DIB_RGB_COLORS ) != g_screenHeight )
  623. {
  624. OutputDebugString( "GetDIBits FAILED to get the full image!\n" );
  625. }
  626. g_pImg->UnlockRect( 0 );
  627. #ifdef BLUR
  628. if ( blur )
  629. {
  630. if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTex ) ) )
  631. {
  632. OutputDebugString( "CreateTexture( g_pTex ) FAILED!\n" );
  633. CleanupD3D();
  634. return false;
  635. }
  636. if ( FAILED( g_pd3dDevice->CreateTexture( g_screenWidth, g_screenHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pRT ) ) )
  637. {
  638. OutputDebugString( "CreateTexture( g_pRT ) FAILED!\n" );
  639. CleanupD3D();
  640. return false;
  641. }
  642. IDirect3DSurface8 *pTexSurf = NULL;
  643. g_pTex->GetSurfaceLevel( 0, &pTexSurf );
  644. IDirect3DSurface8 *pImgSurf = NULL;
  645. g_pImg->GetSurfaceLevel( 0, &pImgSurf );
  646. RECT rect = { 0, 0, g_screenWidth, g_screenHeight };
  647. POINT pt = { 0, 0 };
  648. g_pd3dDevice->CopyRects( pImgSurf, &rect, 1, pTexSurf, &pt );
  649. pTexSurf->Release();
  650. pImgSurf->Release();
  651. }
  652. #endif // BLUR
  653. g_pd3dDevice->SetTexture( 0, g_pImg );
  654. InitTextureStageState( 0, D3DTOP_MODULATE, D3DTA_TEXTURE, D3DTA_TFACTOR );
  655. #ifdef BLUR
  656. if ( blur )
  657. {
  658. g_pd3dDevice->SetTexture( 0, g_pTex );
  659. // g_pd3dDevice->SetTexture( 1, g_pTex );
  660. // g_pd3dDevice->SetTexture( 2, g_pTex );
  661. // g_pd3dDevice->SetTexture( 3, g_pTex );
  662. DWORD op = D3DTOP_DISABLE; // D3DTOP_MULTIPLYADD;
  663. InitTextureStageState( 1, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
  664. InitTextureStageState( 2, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
  665. InitTextureStageState( 3, op, D3DTA_TEXTURE, D3DTA_TFACTOR, D3DTA_CURRENT );
  666. }
  667. #endif // BLUR
  668. return true;
  669. }
  670. void DrawD3DFade( BYTE fade, bool blur )
  671. {
  672. if ( g_pd3dDevice )
  673. {
  674. #ifdef BLUR
  675. if ( g_pTex )
  676. {
  677. if ( blur )
  678. {
  679. IDirect3DSurface8 *pRTSurf = NULL;
  680. g_pRT->GetSurfaceLevel( 0, &pRTSurf );
  681. g_pd3dDevice->SetRenderTarget( pRTSurf, NULL );
  682. if ( g_pBackBuf )
  683. {
  684. g_pBackBuf->Release();
  685. g_pBackBuf = NULL;
  686. }
  687. g_pd3dDevice->BeginScene();
  688. g_pd3dDevice->SetTexture( 0, g_pTex );
  689. g_pd3dDevice->SetTexture( 1, g_pTex );
  690. g_pd3dDevice->SetTexture( 2, g_pTex );
  691. g_pd3dDevice->SetTexture( 3, g_pTex );
  692. g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
  693. g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
  694. g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD );
  695. g_pd3dDevice->SetStreamSource( 0, g_pBlurVB, g_nBlurStride );
  696. g_pd3dDevice->SetVertexShader( g_dwBlurFVF );
  697. DWORD quarter = 0x3f | ( 0x3f << 8 ) | ( 0x3f << 16 ) | ( 0x3f << 24 );
  698. g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, quarter );
  699. g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  700. g_pd3dDevice->EndScene();
  701. pRTSurf->Release();
  702. g_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackBuf );
  703. g_pd3dDevice->SetRenderTarget( g_pBackBuf, NULL );
  704. IDirect3DTexture8 *pTemp = g_pTex;
  705. g_pTex = g_pRT;
  706. g_pRT = pTemp;
  707. g_pd3dDevice->SetTexture( 0, g_pTex );
  708. g_pd3dDevice->SetTexture( 1, NULL );
  709. g_pd3dDevice->SetTexture( 2, NULL );
  710. g_pd3dDevice->SetTexture( 3, NULL );
  711. g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
  712. g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
  713. g_pd3dDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_DISABLE );
  714. g_pd3dDevice->SetStreamSource( 0, g_pDrawVB, g_nDrawStride );
  715. g_pd3dDevice->SetVertexShader( g_dwDrawFVF );
  716. }
  717. }
  718. #endif
  719. g_pd3dDevice->BeginScene();
  720. // DWORD factor = 0xff | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 );
  721. DWORD factor = fade | ( fade << 8 ) | ( fade << 16 ) | ( fade << 24 );
  722. g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, factor );
  723. g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  724. g_pd3dDevice->EndScene();
  725. g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  726. }
  727. }
  728. #endif // USE_D3D8
  729. int g_nTimingIndex = 0;
  730. double g_timings[ 65536 ];
  731. LRESULT CALLBACK WinProc( HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam )
  732. {
  733. switch ( msg )
  734. {
  735. case WM_CREATE:
  736. {
  737. g_timeAtFadeStart = 0.0;
  738. g_nBlurSteps = 0;
  739. g_hBlackFadingWindow = hWnd;
  740. #ifndef USE_D3D8
  741. MONITORINFO mi;
  742. mi.cbSize = sizeof( mi );
  743. if ( GetMonitorInfo( g_hMonitor, &mi ) )
  744. {
  745. SetWindowPos( hWnd, HWND_TOPMOST, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, 0 );
  746. }
  747. #endif
  748. #ifdef USE_D3D8
  749. InitD3D( hWnd, true );
  750. #endif // USE_D3D8
  751. if ( !g_bFadeIn )
  752. {
  753. g_pFrame->ShowWindow( SW_HIDE );
  754. g_pFrame->PostMessage( WM_DESTROY, 0, 0 );
  755. }
  756. InvalidateRect( hWnd, NULL, TRUE );
  757. SetTimer( hWnd, ID_SKIP_FADE_TIMER, 1000, NULL ); // if the fade doesn't start in 1 second, then just jump to the video
  758. SetTimer( hWnd, ID_DRAW_TIMER, 10, NULL ); // draw timer
  759. }
  760. break;
  761. #ifdef USE_D3D8
  762. case WM_TIMER: // WM_ERASEBKGND:
  763. #else
  764. case WM_TIMER: // WM_ERASEBKGND:
  765. // case WM_NCPAINT:
  766. #endif
  767. if ( wparam == ID_DRAW_TIMER )
  768. {
  769. static LARGE_INTEGER s_nPerformanceFrequency;
  770. if ( g_timeAtFadeStart == 0.0 )
  771. {
  772. LARGE_INTEGER nTimeAtFadeStart;
  773. QueryPerformanceCounter( &nTimeAtFadeStart );
  774. QueryPerformanceFrequency( &s_nPerformanceFrequency );
  775. g_timeAtFadeStart = nTimeAtFadeStart.QuadPart / double( s_nPerformanceFrequency.QuadPart );
  776. KillTimer( hWnd, ID_SKIP_FADE_TIMER );
  777. 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
  778. }
  779. LARGE_INTEGER time;
  780. QueryPerformanceCounter( &time );
  781. g_timings[ g_nTimingIndex++ ] = time.QuadPart / double( s_nPerformanceFrequency.QuadPart );
  782. float dt = ( float )( time.QuadPart / double( s_nPerformanceFrequency.QuadPart ) - g_timeAtFadeStart );
  783. bool bFadeFinished = dt >= FADE_TIME;
  784. float fraction = bFadeFinished ? 1.0f : dt / FADE_TIME;
  785. /*
  786. char str[ 256 ];
  787. sprintf( str, "A - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" );
  788. OutputDebugString( str );
  789. */
  790. bool blur = g_bFadeIn && ( int( fraction * MAX_BLUR_STEPS ) > g_nBlurSteps );
  791. if ( blur )
  792. {
  793. ++g_nBlurSteps;
  794. }
  795. BYTE fade = BYTE( fraction * 255.999f );
  796. if ( g_bFadeIn )
  797. {
  798. fade = 255 - fade;
  799. }
  800. /*
  801. char str[ 256 ];
  802. sprintf( str, "fade = %d\n", fade );
  803. OutputDebugString( str );
  804. */
  805. #ifdef USE_D3D8
  806. DrawD3DFade( fade, blur );
  807. #else // USE_D3D8
  808. // HDC hdc = GetDCEx( hWnd, ( HRGN )wparam, DCX_WINDOW | DCX_INTERSECTRGN );
  809. if ( !PatBlt( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, BLACKNESS ) )
  810. {
  811. OutputDebugString( "PatBlt FAILED!\n" );
  812. }
  813. // fade = 128;
  814. BLENDFUNCTION blendfunc = { AC_SRC_OVER, 0, fade, 0 };
  815. if ( !::AlphaBlend( g_hdcBlend, 0, 0, g_screenWidth, g_screenHeight, g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, blendfunc ) )
  816. {
  817. OutputDebugString( "AlphaBlend FAILED!\n" );
  818. }
  819. if ( !BitBlt( ( HDC )wparam, 0, 0, g_screenWidth, g_screenHeight, g_hdcBlend, 0, 0, SRCCOPY ) )
  820. {
  821. OutputDebugString( "BitBlt FAILED!\n" );
  822. }
  823. // ReleaseDC( hWnd, hdc );
  824. // RedrawWindow( hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE );
  825. #endif // USE_D3D8
  826. /*
  827. // char str[ 256 ];
  828. sprintf( str, "B - dt = %f\t time = %f \tfade_finished = %s\n", dt, g_timings[ g_nTimingIndex - 1 ], bFadeFinished ? "true" : "false" );
  829. OutputDebugString( str );
  830. */
  831. if ( !bFadeFinished )
  832. break;
  833. // fall-through intentional
  834. // OutputDebugString( "Fall-through from erase background\n" );
  835. }
  836. // case WM_TIMER:
  837. {
  838. if ( msg == WM_TIMER )
  839. {
  840. /*
  841. char str[ 256 ];
  842. sprintf( str, "Timer 0x%x triggered for window 0x%x\n", wparam, hWnd );
  843. OutputDebugString( str );
  844. */
  845. if ( wparam == ID_DRAW_TIMER )
  846. {
  847. // UpdateWindow( hWnd );
  848. // InvalidateRect( hWnd, NULL, TRUE );
  849. // break;
  850. }
  851. }
  852. KillTimer( hWnd, ID_SKIP_FADE_TIMER );
  853. KillTimer( hWnd, ID_DRAW_TIMER );
  854. if ( !g_bFadeIn )
  855. {
  856. // OutputDebugString( "closing fade window\n" );
  857. ShowWindow( hWnd, SW_HIDE );
  858. PostMessage( hWnd, WM_CLOSE, 0, 0 );
  859. return 1;
  860. }
  861. else if ( !g_bFrameCreated )
  862. {
  863. g_bFrameCreated = true;
  864. #ifdef USE_D3D8
  865. // OutputDebugString( "Cleanup D3D\n" );
  866. CleanupD3D();
  867. #endif
  868. g_pFrame = &g_frame;
  869. g_pFrame->GetWndClassInfo().m_wc.hIcon = LoadIcon( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDI_ICON ) );
  870. RECT rcPos = { CW_USEDEFAULT, 0, 0, 0 };
  871. // OutputDebugString( "Create WMP frame\n" );
  872. if ( g_osVersion < OSV_XP )
  873. {
  874. g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW, 0, ( UINT )0 );
  875. }
  876. else
  877. {
  878. g_pFrame->Create( GetDesktopWindow(), rcPos, _T( "Steam Media Player" ), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, ( UINT )0 );
  879. g_pFrame->ShowWindow( SW_SHOW );
  880. }
  881. // OutputDebugString( "Create WMP frame - done\n" );
  882. }
  883. // close WMP window once we paint the fullscreen fade window
  884. if ( !g_bFadeIn )
  885. {
  886. g_pFrame->ShowWindow( SW_HIDE );
  887. }
  888. }
  889. return 1;
  890. case WM_KEYDOWN:
  891. if ( wparam == VK_ESCAPE )
  892. {
  893. ::DestroyWindow( hWnd );
  894. }
  895. break;
  896. case WM_DESTROY:
  897. g_hBlackFadingWindow = NULL;
  898. #ifdef USE_D3D8
  899. CleanupD3D();
  900. #endif
  901. if ( g_bFrameCreated )
  902. {
  903. g_bFrameCreated = false;
  904. g_pFrame->DestroyWindow();
  905. g_pFrame = NULL;
  906. }
  907. ::PostQuitMessage( 0 );
  908. break;
  909. }
  910. return DefWindowProc( hWnd, msg, wparam, lparam );
  911. }
  912. bool ShowFadeWindow( bool bShow )
  913. {
  914. if ( bShow )
  915. {
  916. g_timeAtFadeStart = 0.0;
  917. g_bFadeIn = false;
  918. SetTimer( g_hBlackFadingWindow, ID_DRAW_TIMER, 10, NULL );
  919. if ( g_pFrame )
  920. {
  921. g_pFrame->ShowWindow( SW_HIDE );
  922. }
  923. #ifdef USE_D3D8
  924. if ( g_osVersion < OSV_XP )
  925. {
  926. ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
  927. }
  928. InitD3D( g_hBlackFadingWindow, false );
  929. #else // USE_D3D8
  930. ::SetWindowPos( g_hBlackFadingWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
  931. // ::ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
  932. #endif // USE_D3D8
  933. InvalidateRect( g_hBlackFadingWindow, NULL, TRUE );
  934. }
  935. else
  936. {
  937. if ( g_osVersion < OSV_XP )
  938. {
  939. // OutputDebugString( "hiding fade window\n" );
  940. ShowWindow( g_hBlackFadingWindow, SW_HIDE );
  941. }
  942. else
  943. {
  944. // OutputDebugString( "Deferring erase on fade window\n" );
  945. ::SetWindowPos( g_hBlackFadingWindow, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_DEFERERASE );
  946. }
  947. }
  948. return true;
  949. }
  950. HWND CreateFullscreenWindow( bool bFadeIn )
  951. {
  952. if ( g_hBlackFadingWindow )
  953. return g_hBlackFadingWindow;
  954. static s_bRegistered = false;
  955. if ( !s_bRegistered )
  956. {
  957. WNDCLASS wc;
  958. wc.style = CS_HREDRAW | CS_VREDRAW;
  959. wc.lpfnWndProc = ( WNDPROC )WinProc;
  960. wc.cbClsExtra = 0;
  961. wc.cbWndExtra = 0;
  962. wc.hInstance = g_hInstance;
  963. wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
  964. wc.hCursor = NULL;
  965. wc.hbrBackground = NULL;
  966. wc.lpszMenuName = NULL;
  967. wc.lpszClassName = "myclass";
  968. if ( !RegisterClass( &wc ) )
  969. return 0;
  970. s_bRegistered = true;
  971. }
  972. g_bFadeIn = bFadeIn;
  973. DWORD windowStyle = WS_POPUP;
  974. #ifndef USE_D3D8
  975. windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE;
  976. #endif
  977. if ( g_osVersion < OSV_XP )
  978. {
  979. windowStyle |= WS_MAXIMIZE | WS_EX_TOPMOST | WS_VISIBLE;
  980. }
  981. MONITORINFO mi;
  982. mi.cbSize = sizeof( mi );
  983. if ( !GetMonitorInfo( g_hMonitor, &mi ) )
  984. {
  985. GetClientRect( GetDesktopWindow(), &mi.rcMonitor );
  986. }
  987. 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 );
  988. #ifndef USE_D3D8
  989. ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
  990. #endif
  991. if ( g_osVersion < OSV_XP )
  992. {
  993. ShowWindow( g_hBlackFadingWindow, SW_SHOWMAXIMIZED );
  994. }
  995. while ( ShowCursor( FALSE ) >= 0 )
  996. ;
  997. return g_hBlackFadingWindow;
  998. }
  999. bool CreateDesktopBitmaps()
  1000. {
  1001. MONITORINFOEX mi;
  1002. mi.cbSize = sizeof( mi );
  1003. if ( !GetMonitorInfo( g_hMonitor, &mi ) )
  1004. return false;
  1005. g_screenWidth = mi.rcMonitor.right - mi.rcMonitor.left;
  1006. g_screenHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
  1007. HDC hdcScreen = CreateDC( mi.szDevice, mi.szDevice, NULL, NULL );
  1008. if ( !hdcScreen )
  1009. return false;
  1010. g_hdcCapture = CreateCompatibleDC( hdcScreen );
  1011. g_hdcBlend = CreateCompatibleDC( hdcScreen );
  1012. if ( !g_hdcCapture || !g_hdcBlend )
  1013. return false;
  1014. if ( ( GetDeviceCaps( hdcScreen, SHADEBLENDCAPS ) & SB_CONST_ALPHA ) == 0 )
  1015. {
  1016. OutputDebugString( "display doesn't support AlphaBlend!\n" );
  1017. }
  1018. if ( ( GetDeviceCaps( hdcScreen, RASTERCAPS ) & RC_BITBLT ) == 0 )
  1019. {
  1020. OutputDebugString( "display doesn't support BitBlt!\n" );
  1021. }
  1022. if ( GetDeviceCaps( hdcScreen, BITSPIXEL ) < 32 )
  1023. {
  1024. OutputDebugString( "display doesn't support 32bpp!\n" );
  1025. }
  1026. if ( g_screenWidth != GetDeviceCaps( hdcScreen, HORZRES ) ||
  1027. g_screenHeight != GetDeviceCaps( hdcScreen, VERTRES ) )
  1028. {
  1029. OutputDebugString( "Screen DC size differs from monitor size!\n" );
  1030. }
  1031. g_hbmCapture = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight );
  1032. g_hbmBlend = CreateCompatibleBitmap( hdcScreen, g_screenWidth, g_screenHeight );
  1033. if ( !g_hbmCapture || !g_hbmBlend )
  1034. return false;
  1035. HGDIOBJ oldCaptureObject = SelectObject( g_hdcCapture, g_hbmCapture );
  1036. HGDIOBJ oldBlendObject = SelectObject( g_hdcBlend, g_hbmBlend );
  1037. if ( !BitBlt( g_hdcCapture, 0, 0, g_screenWidth, g_screenHeight, hdcScreen, 0, 0, SRCCOPY ) )
  1038. return false;
  1039. SelectObject( g_hdcCapture, oldCaptureObject );
  1040. SelectObject( g_hdcBlend, oldBlendObject );
  1041. return true;
  1042. }
  1043. void PrintLastError( const char *pPrefix )
  1044. {
  1045. #ifdef _DEBUG
  1046. DWORD dw = GetLastError();
  1047. LPVOID lpMsgBuf;
  1048. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1049. NULL, dw, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  1050. ( LPTSTR )&lpMsgBuf, 0, NULL );
  1051. OutputDebugString( pPrefix );
  1052. char msg[ 256 ];
  1053. sprintf( msg, "(%d) ", dw );
  1054. OutputDebugString( msg );
  1055. OutputDebugString( ( char * )lpMsgBuf );
  1056. LocalFree( lpMsgBuf );
  1057. #endif
  1058. }
  1059. void KillOtherSMPs()
  1060. {
  1061. DWORD nBytesReturned = 0;
  1062. DWORD procIds[ 1024 ];
  1063. if ( !EnumProcesses( procIds, sizeof( procIds ), &nBytesReturned ) )
  1064. {
  1065. PrintLastError( "EnumProcesses Error: " );
  1066. return;
  1067. }
  1068. DWORD dwCurrentProcessId = GetCurrentProcessId();
  1069. int nProcIds = nBytesReturned / sizeof( DWORD );
  1070. for ( int i = 0; i < nProcIds; ++i )
  1071. {
  1072. if ( procIds[ i ] == dwCurrentProcessId )
  1073. continue;
  1074. if ( procIds[ i ] == 0 ) // system idle process
  1075. continue;
  1076. HANDLE hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, procIds[ i ] );
  1077. if ( !hProcess )
  1078. {
  1079. PrintLastError( "OpenProcess Error: " );
  1080. continue;
  1081. }
  1082. HMODULE hMod[ 1 ];
  1083. DWORD cbNeeded;
  1084. if ( !EnumProcessModules( hProcess, hMod, sizeof( hMod ), &cbNeeded ) )
  1085. {
  1086. PrintLastError( "EnumProcessModules Error: " );
  1087. continue;
  1088. }
  1089. char processName[ 1024 ];
  1090. int nChars = GetModuleBaseName( hProcess, hMod[ 0 ], processName, sizeof( processName ) / sizeof( char ) );
  1091. if ( nChars >= sizeof( processName ) )
  1092. {
  1093. PrintLastError( "GetModuleBaseName Error: " );
  1094. continue;
  1095. }
  1096. if ( strcmp( processName, "smp.exe" ) == 0 )
  1097. {
  1098. OutputDebugString( "!!! Killing smp.exe !!!\n" );
  1099. TerminateProcess( hProcess, 0 );
  1100. }
  1101. if ( !CloseHandle( hProcess ) )
  1102. {
  1103. PrintLastError( "CloseHandle Error: " );
  1104. continue;
  1105. }
  1106. }
  1107. }
  1108. void ParseCommandLine( const char *cmdline, std::vector< std::string > &params )
  1109. {
  1110. params.push_back( "" );
  1111. bool quoted = false;
  1112. for ( const char *cp = cmdline; *cp; ++cp )
  1113. {
  1114. if ( *cp == '\"' )
  1115. {
  1116. quoted = !quoted;
  1117. }
  1118. else if ( isspace( *cp ) && !quoted )
  1119. {
  1120. if ( !params.back().empty() )
  1121. {
  1122. params.push_back( "" );
  1123. }
  1124. }
  1125. else
  1126. {
  1127. params.back().push_back( *cp );
  1128. }
  1129. }
  1130. if ( params.back().empty() )
  1131. {
  1132. params.pop_back();
  1133. }
  1134. }
  1135. /////////////////////////////////////////////////////////////////////////////
  1136. //
  1137. extern "C" int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/ )
  1138. {
  1139. g_hInstance = hInstance;
  1140. KillOtherSMPs();
  1141. g_lpCommandLine = lpCmdLine;
  1142. if ( lpCmdLine == NULL || *lpCmdLine == '\0' )
  1143. return 0;
  1144. std::vector< std::string > params;
  1145. ParseCommandLine( lpCmdLine, params );
  1146. int nParams = params.size();
  1147. for ( int i = 0; i < nParams; ++i )
  1148. {
  1149. if ( params[ i ][ 0 ] == '-' || params[ i ][ 0 ] == '/' )
  1150. {
  1151. const char *pOption = params[ i ].c_str() + 1;
  1152. if ( strcmp( pOption, "reportstats" ) == 0 )
  1153. {
  1154. g_bReportStats = true;
  1155. }
  1156. else if ( strcmp( pOption, "localsteamserver" ) == 0 )
  1157. {
  1158. g_bUseLocalSteamServer = true;
  1159. }
  1160. else if ( strcmp( pOption, "redirect" ) == 0 )
  1161. {
  1162. ++i;
  1163. g_redirectTarget = params[ i ];
  1164. }
  1165. }
  1166. else
  1167. {
  1168. g_URL = params[ i ];
  1169. }
  1170. }
  1171. SetRegistryValue( "Software\\Microsoft\\MediaPlayer\\Preferences\\VideoSettings", "UseVMROverlay", 0, g_dwUseVMROverlayOldValue, g_bUseVMROverlayValueExists );
  1172. atexit( RestoreRegistry );
  1173. LogPlayerEvent( ET_APPLAUNCH, 0.0f );
  1174. lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
  1175. CoInitialize( 0 );
  1176. _Module.Init( ObjectMap, hInstance, &LIBID_ATLLib );
  1177. ::InitCommonControls();
  1178. POINT pt;
  1179. GetCursorPos( &pt );
  1180. g_hMonitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
  1181. if ( !CreateDesktopBitmaps() )
  1182. {
  1183. OutputDebugString( "CreateDesktopBitmaps FAILED!\n" );
  1184. }
  1185. ShowCursor( FALSE );
  1186. CreateFullscreenWindow( true );
  1187. MSG msg;
  1188. while ( GetMessage( &msg, 0, 0, 0 ) )
  1189. {
  1190. TranslateMessage( &msg );
  1191. DispatchMessage( &msg );
  1192. }
  1193. LogPlayerEvent( ET_APPEXIT );
  1194. if ( g_bReportStats )
  1195. {
  1196. UploadStats();
  1197. }
  1198. if ( !g_redirectTarget.empty() )
  1199. {
  1200. ::ShellExecuteA( NULL, "open", g_redirectTarget.c_str(), NULL, NULL, SW_SHOWNORMAL );
  1201. }
  1202. _Module.Term();
  1203. CoUninitialize();
  1204. RestoreRegistry();
  1205. return 0;
  1206. }