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.

384 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // SteamDebugHelperDlg.cpp : implementation file
  9. //
  10. #include "stdafx.h"
  11. #include "SteamDebugHelper.h"
  12. #include "SteamDebugHelperDlg.h"
  13. #include "filesystem.h"
  14. #include "interface.h"
  15. #include "filesystem_tools.h"
  16. #include <io.h>
  17. #include <direct.h>
  18. #include "tier0/icommandline.h"
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define CHECK( cmd ) \
  25. if ( !(cmd) ) \
  26. Error( "%s failed", #cmd );
  27. #define CHECK_1STR( cmd, a ) \
  28. if ( !(cmd) ) \
  29. Error( "%s failed (%s)", #cmd, a );
  30. #define CHECK_2STR( cmd, a, b ) \
  31. if ( !(cmd) ) \
  32. Error( "%s failed (%s, %s)", #cmd, a, b );
  33. /////////////////////////////////////////////////////////////////////////////
  34. // CSteamDebugHelperDlg dialog
  35. CSteamDebugHelperDlg::CSteamDebugHelperDlg(CWnd* pParent /*=NULL*/)
  36. : CDialog(CSteamDebugHelperDlg::IDD, pParent)
  37. {
  38. //{{AFX_DATA_INIT(CSteamDebugHelperDlg)
  39. // NOTE: the ClassWizard will add member initialization here
  40. //}}AFX_DATA_INIT
  41. // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  42. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  43. }
  44. void CSteamDebugHelperDlg::DoDataExchange(CDataExchange* pDX)
  45. {
  46. CDialog::DoDataExchange(pDX);
  47. //{{AFX_DATA_MAP(CSteamDebugHelperDlg)
  48. // NOTE: the ClassWizard will add DDX and DDV calls here
  49. //}}AFX_DATA_MAP
  50. }
  51. BEGIN_MESSAGE_MAP(CSteamDebugHelperDlg, CDialog)
  52. //{{AFX_MSG_MAP(CSteamDebugHelperDlg)
  53. ON_WM_PAINT()
  54. ON_WM_QUERYDRAGICON()
  55. ON_BN_CLICKED(ID_SETUP_FOR_DEBUGGING, OnSetupForDebugging)
  56. ON_BN_CLICKED(ID_UNSETUP_FOR_DEBUGGING, OnUnsetupForDebugging)
  57. ON_BN_CLICKED(ID_START_STEAM, OnStartSteam)
  58. ON_BN_CLICKED(ID_EDIT_CONFIG_FILE, OnEditConfigFile)
  59. ON_BN_CLICKED(ID_EDIT_CHOOSE_CONFIG_FILE, OnEditChooseConfigFile)
  60. //}}AFX_MSG_MAP
  61. END_MESSAGE_MAP()
  62. /////////////////////////////////////////////////////////////////////////////
  63. // CSteamDebugHelperDlg message handlers
  64. SpewRetval_t MySpewOutput( SpewType_t spewType, char const *pMsg )
  65. {
  66. if ( spewType == SPEW_ERROR )
  67. {
  68. ::MessageBox( NULL, pMsg, "Error", MB_OK | MB_TASKMODAL );
  69. TerminateProcess( GetCurrentProcess(), 1 );
  70. }
  71. if ( spewType == SPEW_ASSERT )
  72. return SPEW_DEBUGGER;
  73. return SPEW_CONTINUE;
  74. }
  75. BOOL CSteamDebugHelperDlg::OnInitDialog()
  76. {
  77. CDialog::OnInitDialog();
  78. // Set the icon for this dialog. The framework does this automatically
  79. // when the application's main window is not a dialog
  80. SetIcon(m_hIcon, TRUE); // Set big icon
  81. SetIcon(m_hIcon, FALSE); // Set small icon
  82. SpewOutputFunc( MySpewOutput );
  83. // Load the file system.
  84. CommandLine()->CreateCmdLine( __argc, __argv );
  85. FileSystem_Init( NULL, 0, FS_INIT_COMPATIBILITY_MODE );
  86. if ( __argc >= 2 )
  87. {
  88. SetConfigFilename( __argv[1] );
  89. }
  90. // Make sure the config file parses.
  91. KeyValues *pTest = LoadConfigFile();
  92. pTest->deleteThis();
  93. return TRUE; // return TRUE unless you set the focus to a control
  94. }
  95. // If you add a minimize button to your dialog, you will need the code below
  96. // to draw the icon. For MFC applications using the document/view model,
  97. // this is automatically done for you by the framework.
  98. void CSteamDebugHelperDlg::OnPaint()
  99. {
  100. if (IsIconic())
  101. {
  102. CPaintDC dc(this); // device context for painting
  103. SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  104. // Center icon in client rectangle
  105. int cxIcon = GetSystemMetrics(SM_CXICON);
  106. int cyIcon = GetSystemMetrics(SM_CYICON);
  107. CRect rect;
  108. GetClientRect(&rect);
  109. int x = (rect.Width() - cxIcon + 1) / 2;
  110. int y = (rect.Height() - cyIcon + 1) / 2;
  111. // Draw the icon
  112. dc.DrawIcon(x, y, m_hIcon);
  113. }
  114. else
  115. {
  116. CDialog::OnPaint();
  117. }
  118. }
  119. // The system calls this to obtain the cursor to display while the user drags
  120. // the minimized window.
  121. HCURSOR CSteamDebugHelperDlg::OnQueryDragIcon()
  122. {
  123. return (HCURSOR) m_hIcon;
  124. }
  125. KeyValues* CSteamDebugHelperDlg::LoadConfigFile()
  126. {
  127. if ( m_ConfigFilename.GetLength() == 0 )
  128. return NULL;
  129. KeyValues *pKV = ::new KeyValues( "" );
  130. if ( !pKV->LoadFromFile( g_pFileSystem, m_ConfigFilename ) )
  131. {
  132. Error( "Error parsing %s.", m_ConfigFilename );
  133. }
  134. // Get values from the kv file.
  135. m_pSteamAppCfg = pKV->FindKey( "SteamApp.Cfg" );
  136. m_pSourceExeDir = pKV->GetString( "SourceExeDir", NULL );
  137. m_pSteamAppDir = pKV->GetString( "SteamAppDir", NULL );
  138. if ( !m_pSteamAppCfg || !m_pSourceExeDir || !m_pSteamAppDir )
  139. Error( "Missing one or more keys in the config file." );
  140. // Steam base dir is the app dir but 3 slashes back.
  141. Q_strncpy( m_SteamBaseDir, m_pSteamAppDir, sizeof( m_SteamBaseDir ) );
  142. for ( int i=0; i < 3; i++ )
  143. {
  144. char *pSlash = strrchr( m_SteamBaseDir, '/' );
  145. if ( !pSlash )
  146. pSlash = strrchr( m_SteamBaseDir, '\\' );
  147. if ( !pSlash )
  148. Error( "SteamAppDir %s invalid.", m_pSteamAppDir );
  149. else
  150. *pSlash = 0;
  151. }
  152. return pKV;
  153. }
  154. void CSteamDebugHelperDlg::OnSetupForDebugging()
  155. {
  156. char src[512], dest[512];
  157. KeyValues *pCur;
  158. KeyValues *pKV = LoadConfigFile();
  159. if ( !pKV )
  160. return;
  161. HCURSOR hOldCursor = GetCursor();
  162. SetCursor( LoadCursor( AfxGetInstanceHandle(), IDC_WAIT ) );
  163. // steam.dll
  164. Q_snprintf( src, sizeof( src ), "%s\\steam.dll", m_SteamBaseDir );
  165. Q_snprintf( dest, sizeof( dest ), "%s\\steam.dll", m_pSteamAppDir );
  166. CHECK_2STR( CopyFile( src, dest, false ), src, dest );
  167. // steam.cfg
  168. Q_snprintf( src, sizeof( src ), "%s\\steam.cfg", m_SteamBaseDir );
  169. Q_snprintf( dest, sizeof( dest ), "%s\\steam.cfg", m_pSteamAppDir );
  170. CopyFile( src, dest, false );
  171. // now build steamapp.cfg
  172. Q_snprintf( dest, sizeof( dest ), "%s\\SteamApp.cfg", m_pSteamAppDir );
  173. FILE *fp = fopen( dest, "wt" );
  174. CHECK( fp );
  175. for ( pCur=m_pSteamAppCfg->GetFirstValue(); pCur; pCur=pCur->GetNextValue() )
  176. {
  177. fprintf( fp, "%s\n", pCur->GetString() );
  178. }
  179. fprintf( fp, "SteamInstallPath=\"%s\"", m_SteamBaseDir );
  180. fclose( fp );
  181. // Now copy each binary up there and make it read-only.
  182. for ( pCur=pKV->GetFirstValue(); pCur; pCur=pCur->GetNextValue() )
  183. {
  184. const char *pName = pCur->GetName();
  185. if ( Q_stricmp( pName, "binary" ) == 0 )
  186. {
  187. Q_snprintf( src, sizeof( src ), "%s\\%s", m_pSourceExeDir, pCur->GetString() );
  188. Q_snprintf( dest, sizeof( dest ), "%s\\%s", m_pSteamAppDir, pCur->GetString() );
  189. if ( _access( dest, 0 ) == 0 )
  190. {
  191. CHECK_1STR( SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL ), dest );
  192. }
  193. CHECK_2STR( CopyFile( src, dest, false ), src, dest );
  194. CHECK_1STR( SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY ), dest );
  195. }
  196. }
  197. SetCursor( hOldCursor );
  198. MessageBox( "Setup successfully!", MB_OK );
  199. //pKV->deleteThis(); // note: leak the memory here knowingly to avoid warnings from the stupid way keyvalues overload memory allocation
  200. }
  201. void CSteamDebugHelperDlg::OnUnsetupForDebugging()
  202. {
  203. KeyValues *pKV = LoadConfigFile();
  204. char dest[512];
  205. KeyValues *pCur;
  206. // Delete the steamapp.cfg, steam.dll, and steam.cfg files.
  207. Q_snprintf( dest, sizeof( dest ), "%s\\steam.dll", m_pSteamAppDir );
  208. CHECK_1STR( SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL ), dest );
  209. CHECK_1STR( DeleteFile( dest ), dest );
  210. // steam.cfg
  211. Q_snprintf( dest, sizeof( dest ), "%s\\steam.cfg", m_pSteamAppDir );
  212. SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL );
  213. DeleteFile( dest );
  214. // steamapp.cfg
  215. Q_snprintf( dest, sizeof( dest ), "%s\\steamapp.cfg", m_pSteamAppDir );
  216. CHECK_1STR( SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL ), dest );
  217. CHECK_1STR( DeleteFile( dest ), dest );
  218. for ( pCur=pKV->GetFirstValue(); pCur; pCur=pCur->GetNextValue() )
  219. {
  220. const char *pName = pCur->GetName();
  221. if ( Q_stricmp( pName, "binary" ) == 0 )
  222. {
  223. Q_snprintf( dest, sizeof( dest ), "%s\\%s", m_pSteamAppDir, pCur->GetString() );
  224. if ( _access( dest, 0 ) == 0 )
  225. {
  226. CHECK_1STR( SetFileAttributes( dest, FILE_ATTRIBUTE_NORMAL ), dest );
  227. CHECK_1STR( DeleteFile( dest ), dest );
  228. }
  229. }
  230. }
  231. MessageBox( "Un-setup successfully!", MB_OK );
  232. //pKV->deleteThis(); // note: leak the memory here knowingly to avoid warnings from the stupid way keyvalues overload memory allocation
  233. }
  234. void CSteamDebugHelperDlg::OnStartSteam()
  235. {
  236. STARTUPINFO si;
  237. memset( &si, 0, sizeof( si ) );
  238. si.cb = sizeof( si );
  239. PROCESS_INFORMATION pi;
  240. char dest[512];
  241. Q_snprintf( dest, sizeof( dest ), "%s\\steam.exe", m_SteamBaseDir );
  242. CreateProcess(
  243. dest, // app name
  244. NULL, // command line
  245. NULL, // process attr
  246. NULL, // thread attr
  247. false, // inherit handles
  248. 0, // flags
  249. NULL, // environment
  250. m_SteamBaseDir, // cur directory
  251. &si, // startup info
  252. &pi // process info
  253. );
  254. }
  255. void CSteamDebugHelperDlg::OnEditConfigFile()
  256. {
  257. char str[512];
  258. Q_snprintf( str, sizeof( str ), "notepad \"%s\"", m_ConfigFilename );
  259. STARTUPINFO si;
  260. memset( &si, 0, sizeof( si ) );
  261. si.cb = sizeof( si );
  262. PROCESS_INFORMATION pi;
  263. CreateProcess(
  264. NULL, // app name
  265. str, // command line
  266. NULL, // process attr
  267. NULL, // thread attr
  268. false, // inherit handles
  269. 0, // flags
  270. NULL, // environment
  271. NULL, // cur directory
  272. &si, // startup info
  273. &pi // process info
  274. );
  275. }
  276. void CSteamDebugHelperDlg::OnEditChooseConfigFile()
  277. {
  278. CFileDialog dlg(
  279. true,
  280. "cfg",
  281. NULL,
  282. 0,
  283. "CFG Files (*.cfg)|*.cfg||",
  284. this );
  285. if ( dlg.DoModal() == IDOK )
  286. {
  287. SetConfigFilename( dlg.GetPathName() );
  288. }
  289. }
  290. void CSteamDebugHelperDlg::SetConfigFilename( const char *pName )
  291. {
  292. char absPath[MAX_PATH];
  293. MakeAbsolutePath( absPath, sizeof( absPath ), pName );
  294. if ( _access( absPath, 0 ) == 0 )
  295. {
  296. m_ConfigFilename = absPath;
  297. }
  298. else
  299. {
  300. char str[512];
  301. Q_snprintf( str, sizeof( str ), "%s doesn't exist.", absPath );
  302. AfxMessageBox( str, MB_OK );
  303. return;
  304. }
  305. m_ConfigFilename = absPath;
  306. const char *pConfigFilename = absPath;
  307. const char *pTest1 = strrchr( pConfigFilename, '\\' ) + 1;
  308. const char *pTest2 = strrchr( pConfigFilename, '/' ) + 1;
  309. const char *pBaseName = max( pTest1, max( pTest2, pConfigFilename ) );
  310. SetWindowText( CString( "SteamDebugHelper - " ) + pBaseName );
  311. ::EnableWindow( ::GetDlgItem( m_hWnd, ID_EDIT_CONFIG_FILE ), true );
  312. ::EnableWindow( ::GetDlgItem( m_hWnd, ID_SETUP_FOR_DEBUGGING ), true );
  313. ::EnableWindow( ::GetDlgItem( m_hWnd, ID_UNSETUP_FOR_DEBUGGING ), true );
  314. }