llappviewerwin32.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:18k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file llappviewerwin32.cpp
  3.  * @brief The LLAppViewerWin32 class definitions
  4.  *
  5.  * $LicenseInfo:firstyear=2007&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2007-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */ 
  32. #include "llviewerprecompiledheaders.h"
  33. #if defined(_DEBUG)
  34. # if _MSC_VER >= 1400 // Visual C++ 2005 or later
  35. # define WINDOWS_CRT_MEM_CHECKS 1
  36. # endif
  37. #endif
  38. #include "llappviewerwin32.h"
  39. #include "llmemtype.h"
  40. #include "llwindowwin32.cpp" // *FIX: for setting gIconResource.
  41. #include "res/resource.h" // *FIX: for setting gIconResource.
  42. #include <fcntl.h> //_O_APPEND
  43. #include <io.h> //_open_osfhandle()
  44. #include <errorrep.h> // for AddERExcludedApplicationA()
  45. #include <process.h> // _spawnl()
  46. #include <tchar.h> // For TCHAR support
  47. #include "llviewercontrol.h"
  48. #include "lldxhardware.h"
  49. #include "llweb.h"
  50. #include "llsecondlifeurls.h"
  51. #include "llwindebug.h"
  52. #include "llviewernetwork.h"
  53. #include "llmd5.h"
  54. #include "llfindlocale.h"
  55. #include "llcommandlineparser.h"
  56. #include "lltrans.h"
  57. // *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
  58. // The lib was compiled under VS2005 - in VS2003 we need to remap assert
  59. #ifdef LL_DEBUG
  60. #ifdef LL_MSVC7 
  61. extern "C" {
  62.     void _wassert(const wchar_t * _Message, const wchar_t *_File, unsigned _Line)
  63.     {
  64.         llerrs << _Message << llendl;
  65.     }
  66. }
  67. #endif
  68. #endif
  69. const std::string LLAppViewerWin32::sWindowClass = "Second Life";
  70. LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
  71. {
  72.     // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
  73. //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
  74.     // *TODO: Translate the signals/exceptions into cross-platform stuff
  75. // Windows implementation
  76.     _tprintf( _T("Entering Windows Exception Handler...n") );
  77. llinfos << "Entering Windows Exception Handler..." << llendl;
  78. // Make sure the user sees something to indicate that the app crashed.
  79. LONG retval;
  80. if (LLApp::isError())
  81. {
  82.     _tprintf( _T("Got another fatal signal while in the error handler, die now!n") );
  83. llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
  84. retval = EXCEPTION_EXECUTE_HANDLER;
  85. return retval;
  86. }
  87. // Generate a minidump if we can.
  88. // Before we wake the error thread...
  89. // Which will start the crash reporting.
  90. LLWinDebug::generateCrashStacks(exception_infop);
  91. // Flag status to error, so thread_error starts its work
  92. LLApp::setError();
  93. // Block in the exception handler until the app has stopped
  94. // This is pretty sketchy, but appears to work just fine
  95. while (!LLApp::isStopped())
  96. {
  97. ms_sleep(10);
  98. }
  99. //
  100. // At this point, we always want to exit the app.  There's no graceful
  101. // recovery for an unhandled exception.
  102. // 
  103. // Just kill the process.
  104. retval = EXCEPTION_EXECUTE_HANDLER;
  105. return retval;
  106. }
  107. // Create app mutex creates a unique global windows object. 
  108. // If the object can be created it returns true, otherwise
  109. // it returns false. The false result can be used to determine 
  110. // if another instance of a second life app (this vers. or later)
  111. // is running.
  112. // *NOTE: Do not use this method to run a single instance of the app.
  113. // This is intended to help debug problems with the cross-platform 
  114. // locked file method used for that purpose.
  115. bool create_app_mutex()
  116. {
  117. bool result = true;
  118. LPCWSTR unique_mutex_name = L"SecondLifeAppMutex";
  119. HANDLE hMutex;
  120. hMutex = CreateMutex(NULL, TRUE, unique_mutex_name); 
  121. if(GetLastError() == ERROR_ALREADY_EXISTS) 
  122. {     
  123. result = false;
  124. }
  125. return result;
  126. }
  127. //#define DEBUGGING_SEH_FILTER 1
  128. #if DEBUGGING_SEH_FILTER
  129. # define WINMAIN DebuggingWinMain
  130. #else
  131. # define WINMAIN WinMain
  132. #endif
  133. int APIENTRY WINMAIN(HINSTANCE hInstance,
  134.                      HINSTANCE hPrevInstance,
  135.                      LPSTR     lpCmdLine,
  136.                      int       nCmdShow)
  137. {
  138. LLMemType mt1(LLMemType::MTYPE_STARTUP);
  139. const S32 MAX_HEAPS = 255;
  140. DWORD heap_enable_lfh_error[MAX_HEAPS];
  141. S32 num_heaps = 0;
  142. #if WINDOWS_CRT_MEM_CHECKS && !INCLUDE_VLD
  143. _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); // dump memory leaks on exit
  144. #elif 1
  145. // Experimental - enable the low fragmentation heap
  146. // This results in a 2-3x improvement in opening a new Inventory window (which uses a large numebr of allocations)
  147. // Note: This won't work when running from the debugger unless the _NO_DEBUG_HEAP environment variable is set to 1
  148. _CrtSetDbgFlag(0); // default, just making explicit
  149. ULONG ulEnableLFH = 2;
  150. HANDLE* hHeaps = new HANDLE[MAX_HEAPS];
  151. num_heaps = GetProcessHeaps(MAX_HEAPS, hHeaps);
  152. for(S32 i = 0; i < num_heaps; i++)
  153. {
  154. bool success = HeapSetInformation(hHeaps[i], HeapCompatibilityInformation, &ulEnableLFH, sizeof(ulEnableLFH));
  155. if (success)
  156. heap_enable_lfh_error[i] = 0;
  157. else
  158. heap_enable_lfh_error[i] = GetLastError();
  159. }
  160. #endif
  161. // *FIX: global
  162. gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
  163. LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
  164. LLWinDebug::initExceptionHandler(viewer_windows_exception_handler); 
  165. viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
  166. // Set a debug info flag to indicate if multiple instances are running.
  167. bool found_other_instance = !create_app_mutex();
  168. gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);
  169. bool ok = viewer_app_ptr->init();
  170. if(!ok)
  171. {
  172. llwarns << "Application init failed." << llendl;
  173. return -1;
  174. }
  175. // Have to wait until after logging is initialized to display LFH info
  176. if (num_heaps > 0)
  177. {
  178. llinfos << "Attempted to enable LFH for " << num_heaps << " heaps." << llendl;
  179. for(S32 i = 0; i < num_heaps; i++)
  180. {
  181. if (heap_enable_lfh_error[i])
  182. {
  183. llinfos << "  Failed to enable LFH for heap: " << i << " Error: " << heap_enable_lfh_error[i] << llendl;
  184. }
  185. }
  186. }
  187. // Run the application main loop
  188. if(!LLApp::isQuitting()) 
  189. {
  190. viewer_app_ptr->mainLoop();
  191. }
  192. if (!LLApp::isError())
  193. {
  194. //
  195. // We don't want to do cleanup here if the error handler got called -
  196. // the assumption is that the error handler is responsible for doing
  197. // app cleanup if there was a problem.
  198. //
  199. #if WINDOWS_CRT_MEM_CHECKS
  200.     llinfos << "CRT Checking memory:" << llendflush;
  201. if (!_CrtCheckMemory())
  202. {
  203. llwarns << "_CrtCheckMemory() failed at prior to cleanup!" << llendflush;
  204. }
  205. else
  206. {
  207. llinfos << " No corruption detected." << llendflush;
  208. }
  209. #endif
  210. gGLActive = TRUE;
  211. viewer_app_ptr->cleanup();
  212. #if WINDOWS_CRT_MEM_CHECKS
  213.     llinfos << "CRT Checking memory:" << llendflush;
  214. if (!_CrtCheckMemory())
  215. {
  216. llwarns << "_CrtCheckMemory() failed after cleanup!" << llendflush;
  217. }
  218. else
  219. {
  220. llinfos << " No corruption detected." << llendflush;
  221. }
  222. #endif
  223.  
  224. }
  225. delete viewer_app_ptr;
  226. viewer_app_ptr = NULL;
  227. //start updater
  228. if(LLAppViewer::sUpdaterInfo)
  229. {
  230. _spawnl(_P_NOWAIT, LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), LLAppViewer::sUpdaterInfo->mParams.str().c_str(), NULL);
  231. delete LLAppViewer::sUpdaterInfo ;
  232. LLAppViewer::sUpdaterInfo = NULL ;
  233. }
  234. return 0;
  235. }
  236. #if DEBUGGING_SEH_FILTER
  237. // The compiler doesn't like it when you use __try/__except blocks
  238. // in a method that uses object destructors. Go figure.
  239. // This winmain just calls the real winmain inside __try.
  240. // The __except calls our exception filter function. For debugging purposes.
  241. int APIENTRY WinMain(HINSTANCE hInstance,
  242.                      HINSTANCE hPrevInstance,
  243.                      LPSTR     lpCmdLine,
  244.                      int       nCmdShow)
  245. {
  246.     __try
  247.     {
  248.         WINMAIN(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
  249.     }
  250.     __except( viewer_windows_exception_handler( GetExceptionInformation() ) )
  251.     {
  252.         _tprintf( _T("Exception handled.n") );
  253.     }
  254. }
  255. #endif
  256. void LLAppViewerWin32::disableWinErrorReporting()
  257. {
  258. const char win_xp_string[] = "Microsoft Windows XP";
  259. BOOL is_win_xp = ( getOSInfo().getOSString().substr(0, strlen(win_xp_string) ) == win_xp_string ); /* Flawfinder: ignore*/
  260. if( is_win_xp )
  261. {
  262. // Note: we need to use run-time dynamic linking, because load-time dynamic linking will fail
  263. // on systems that don't have the library installed (all non-Windows XP systems)
  264. HINSTANCE fault_rep_dll_handle = LoadLibrary(L"faultrep.dll"); /* Flawfinder: ignore */
  265. if( fault_rep_dll_handle )
  266. {
  267. pfn_ADDEREXCLUDEDAPPLICATIONA pAddERExcludedApplicationA  = (pfn_ADDEREXCLUDEDAPPLICATIONA) GetProcAddress(fault_rep_dll_handle, "AddERExcludedApplicationA");
  268. if( pAddERExcludedApplicationA )
  269. {
  270. // Strip the path off the name
  271. const char* executable_name = gDirUtilp->getExecutableFilename().c_str();
  272. if( 0 == pAddERExcludedApplicationA( executable_name ) )
  273. {
  274. U32 error_code = GetLastError();
  275. llinfos << "AddERExcludedApplication() failed with error code " << error_code << llendl;
  276. }
  277. else
  278. {
  279. llinfos << "AddERExcludedApplication() success for " << executable_name << llendl;
  280. }
  281. }
  282. FreeLibrary( fault_rep_dll_handle );
  283. }
  284. }
  285. }
  286. const S32 MAX_CONSOLE_LINES = 500;
  287. void create_console()
  288. {
  289. int h_con_handle;
  290. long l_std_handle;
  291. CONSOLE_SCREEN_BUFFER_INFO coninfo;
  292. FILE *fp;
  293. // allocate a console for this app
  294. AllocConsole();
  295. // set the screen buffer to be big enough to let us scroll text
  296. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
  297. coninfo.dwSize.Y = MAX_CONSOLE_LINES;
  298. SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
  299. // redirect unbuffered STDOUT to the console
  300. l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
  301. h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
  302. fp = _fdopen( h_con_handle, "w" );
  303. *stdout = *fp;
  304. setvbuf( stdout, NULL, _IONBF, 0 );
  305. // redirect unbuffered STDIN to the console
  306. l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE);
  307. h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
  308. fp = _fdopen( h_con_handle, "r" );
  309. *stdin = *fp;
  310. setvbuf( stdin, NULL, _IONBF, 0 );
  311. // redirect unbuffered STDERR to the console
  312. l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE);
  313. h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
  314. fp = _fdopen( h_con_handle, "w" );
  315. *stderr = *fp;
  316. setvbuf( stderr, NULL, _IONBF, 0 );
  317. }
  318. LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) :
  319.     mCmdLine(cmd_line)
  320. {
  321. }
  322. LLAppViewerWin32::~LLAppViewerWin32()
  323. {
  324. }
  325. bool LLAppViewerWin32::init()
  326. {
  327. // Platform specific initialization.
  328. // Turn off Windows XP Error Reporting
  329. // (Don't send our data to Microsoft--at least until we are Logo approved and have a way
  330. // of getting the data back from them.)
  331. //
  332. llinfos << "Turning off Windows error reporting." << llendl;
  333. disableWinErrorReporting();
  334. return LLAppViewer::init();
  335. }
  336. bool LLAppViewerWin32::cleanup()
  337. {
  338. bool result = LLAppViewer::cleanup();
  339. gDXHardware.cleanup();
  340. return result;
  341. }
  342. bool LLAppViewerWin32::initLogging()
  343. {
  344. // Remove the crash stack log from previous executions.
  345. // Since we've started logging a new instance of the app, we can assume 
  346. // *NOTE: This should happen before the we send a 'previous instance froze'
  347. // crash report, but it must happen after we initialize the DirUtil.
  348. LLWinDebug::clearCrashStacks();
  349. return LLAppViewer::initLogging();
  350. }
  351. void LLAppViewerWin32::initConsole()
  352. {
  353. // pop up debug console
  354. create_console();
  355. return LLAppViewer::initConsole();
  356. }
  357. void write_debug_dx(const char* str)
  358. {
  359. std::string value = gDebugInfo["DXInfo"].asString();
  360. value += str;
  361. gDebugInfo["DXInfo"] = value;
  362. }
  363. void write_debug_dx(const std::string& str)
  364. {
  365. write_debug_dx(str.c_str());
  366. }
  367. bool LLAppViewerWin32::initHardwareTest()
  368. {
  369. //
  370. // Do driver verification and initialization based on DirectX
  371. // hardware polling and driver versions
  372. //
  373. if (FALSE == gSavedSettings.getBOOL("NoHardwareProbe"))
  374. {
  375. BOOL vram_only = !gSavedSettings.getBOOL("ProbeHardwareOnStartup");
  376. // per DEV-11631 - disable hardware probing for everything
  377. // but vram.
  378. vram_only = TRUE;
  379. LLSplashScreen::update(LLTrans::getString("StartupDetectingHardware"));
  380. LL_DEBUGS("AppInit") << "Attempting to poll DirectX for hardware info" << LL_ENDL;
  381. gDXHardware.setWriteDebugFunc(write_debug_dx);
  382. BOOL probe_ok = gDXHardware.getInfo(vram_only);
  383. if (!probe_ok
  384. && gWarningSettings.getBOOL("AboutDirectX9"))
  385. {
  386. LL_WARNS("AppInit") << "DirectX probe failed, alerting user." << LL_ENDL;
  387. // Warn them that runnin without DirectX 9 will
  388. // not allow us to tell them about driver issues
  389. std::ostringstream msg;
  390. msg << LLTrans::getString ("MBNoDirectX");
  391. S32 button = OSMessageBox(
  392. msg.str(),
  393. LLTrans::getString("MBWarning"),
  394. OSMB_YESNO);
  395. if (OSBTN_NO== button)
  396. {
  397. LL_INFOS("AppInit") << "User quitting after failed DirectX 9 detection" << LL_ENDL;
  398. LLWeb::loadURLExternal(DIRECTX_9_URL);
  399. return false;
  400. }
  401. gWarningSettings.setBOOL("AboutDirectX9", FALSE);
  402. }
  403. LL_DEBUGS("AppInit") << "Done polling DirectX for hardware info" << LL_ENDL;
  404. // Only probe once after installation
  405. gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
  406. // Disable so debugger can work
  407. std::ostringstream splash_msg;
  408. splash_msg << LLTrans::getString("StartupLoading") << " " << LLAppViewer::instance()->getSecondLifeTitle() << "...";
  409. LLSplashScreen::update(splash_msg.str());
  410. }
  411. if (!restoreErrorTrap())
  412. {
  413. LL_WARNS("AppInit") << " Someone took over my exception handler (post hardware probe)!" << LL_ENDL;
  414. }
  415. gGLManager.mVRAM = gDXHardware.getVRAM();
  416. LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL;
  417. return true;
  418. }
  419. bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
  420. {
  421. if (!clp.parseCommandLineString(mCmdLine))
  422. {
  423. return false;
  424. }
  425. // Find the system language.
  426. FL_Locale *locale = NULL;
  427. FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
  428. if (success != 0)
  429. {
  430. if (success >= 2 && locale->lang) // confident!
  431. {
  432. LL_INFOS("AppInit") << "Language: " << ll_safe_string(locale->lang) << LL_ENDL;
  433. LL_INFOS("AppInit") << "Location: " << ll_safe_string(locale->country) << LL_ENDL;
  434. LL_INFOS("AppInit") << "Variant: " << ll_safe_string(locale->variant) << LL_ENDL;
  435. LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
  436. if(c)
  437. {
  438. c->setValue(std::string(locale->lang), false);
  439. }
  440. }
  441. }
  442. FL_FreeLocale(&locale);
  443. return true;
  444. }
  445. bool LLAppViewerWin32::restoreErrorTrap()
  446. {
  447. return LLWinDebug::checkExceptionHandler();
  448. }
  449. void LLAppViewerWin32::handleSyncCrashTrace()
  450. {
  451. // do nothing
  452. }
  453. void LLAppViewerWin32::handleCrashReporting(bool reportFreeze)
  454. {
  455. const char* logger_name = "win_crash_logger.exe";
  456. std::string exe_path = gDirUtilp->getExecutableDir();
  457. exe_path += gDirUtilp->getDirDelimiter();
  458. exe_path += logger_name;
  459. const char* arg_str = logger_name;
  460. // *NOTE:Mani - win_crash_logger.exe no longer parses command line options.
  461. if(reportFreeze)
  462. {
  463. // Spawn crash logger.
  464. // NEEDS to wait until completion, otherwise log files will get smashed.
  465. _spawnl(_P_WAIT, exe_path.c_str(), arg_str, NULL);
  466. }
  467. else
  468. {
  469. S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
  470. if(cb != CRASH_BEHAVIOR_NEVER_SEND)
  471. {
  472. _spawnl(_P_NOWAIT, exe_path.c_str(), arg_str, NULL);
  473. }
  474. }
  475. }
  476. //virtual
  477. bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
  478. {
  479. wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
  480. mbstowcs(window_class, sWindowClass.c_str(), 255);
  481. window_class[255] = 0;
  482. // Use the class instead of the window name.
  483. HWND other_window = FindWindow(window_class, NULL);
  484. if (other_window != NULL)
  485. {
  486. lldebugs << "Found other window with the name '" << getWindowTitle() << "'" << llendl;
  487. COPYDATASTRUCT cds;
  488. const S32 SLURL_MESSAGE_TYPE = 0;
  489. cds.dwData = SLURL_MESSAGE_TYPE;
  490. cds.cbData = url.length() + 1;
  491. cds.lpData = (void*)url.c_str();
  492. LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
  493. lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
  494.  << getWindowTitle() << "' returned " << msg_result << llendl;
  495. return true;
  496. }
  497. return false;
  498. }
  499. std::string LLAppViewerWin32::generateSerialNumber()
  500. {
  501. char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore
  502. serial_md5[0] = 0;
  503. DWORD serial = 0;
  504. DWORD flags = 0;
  505. BOOL success = GetVolumeInformation(
  506. L"C:\",
  507. NULL, // volume name buffer
  508. 0, // volume name buffer size
  509. &serial, // volume serial
  510. NULL, // max component length
  511. &flags, // file system flags
  512. NULL, // file system name buffer
  513. 0); // file system name buffer size
  514. if (success)
  515. {
  516. LLMD5 md5;
  517. md5.update( (unsigned char*)&serial, sizeof(DWORD));
  518. md5.finalize();
  519. md5.hex_digest(serial_md5);
  520. }
  521. else
  522. {
  523. llwarns << "GetVolumeInformation failed" << llendl;
  524. }
  525. return serial_md5;
  526. }