00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llappviewerwin32.h"
00035
00036 #include "llmemtype.h"
00037
00038 #include "llwindowwin32.cpp"
00039 #include "res/resource.h"
00040
00041 #include <fcntl.h>
00042 #include <io.h>
00043 #include <errorrep.h>
00044 #include <process.h>
00045 #include <tchar.h>
00046
00047 #include "llviewercontrol.h"
00048 #include "lldxhardware.h"
00049
00050 #include "llweb.h"
00051 #include "llsecondlifeurls.h"
00052
00053 #include "llwindebug.h"
00054
00055 #include "llviewernetwork.h"
00056 #include "llmd5.h"
00057 #include "llfindlocale.h"
00058
00059 #include "llcommandlineparser.h"
00060
00061 LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop)
00062 {
00063
00064
00065
00066
00067 llinfos << "Entering Windows Exception Handler..." << llendl;
00068
00069
00070 LONG retval;
00071
00072 if (LLApp::isError())
00073 {
00074 llwarns << "Got another fatal signal while in the error handler, die now!" << llendl;
00075 retval = EXCEPTION_EXECUTE_HANDLER;
00076 return retval;
00077 }
00078
00079
00080
00081
00082 LLWinDebug::generateCrashStacks(exception_infop);
00083
00084
00085 LLApp::setError();
00086
00087
00088
00089 while (!LLApp::isStopped())
00090 {
00091 ms_sleep(10);
00092 }
00093
00094
00095
00096
00097
00098
00099 retval = EXCEPTION_EXECUTE_HANDLER;
00100 return retval;
00101 }
00102
00103
00104 #if DEBUGGING_SEH_FILTER
00105 # define WINMAIN DebuggingWinMain
00106 #else
00107 # define WINMAIN WinMain
00108 #endif
00109
00110 int APIENTRY WINMAIN(HINSTANCE hInstance,
00111 HINSTANCE hPrevInstance,
00112 LPSTR lpCmdLine,
00113 int nCmdShow)
00114 {
00115 LLMemType mt1(LLMemType::MTYPE_STARTUP);
00116
00117
00118 gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
00119
00120 LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
00121
00122 LLWinDebug::initExceptionHandler(viewer_windows_exception_handler);
00123
00124 viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
00125
00126 bool ok = viewer_app_ptr->init();
00127 if(!ok)
00128 {
00129 llwarns << "Application init failed." << llendl;
00130 return -1;
00131 }
00132
00133
00134 if(!LLApp::isQuitting())
00135 {
00136 viewer_app_ptr->mainLoop();
00137 }
00138
00139 if (!LLApp::isError())
00140 {
00141
00142
00143
00144
00145
00146 viewer_app_ptr->cleanup();
00147 }
00148 delete viewer_app_ptr;
00149 viewer_app_ptr = NULL;
00150 return 0;
00151 }
00152
00153 #if DEBUGGING_SEH_FILTER
00154
00155
00156
00157
00158 int APIENTRY WinMain(HINSTANCE hInstance,
00159 HINSTANCE hPrevInstance,
00160 LPSTR lpCmdLine,
00161 int nCmdShow)
00162 {
00163 __try
00164 {
00165 WINMAIN(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
00166 }
00167 __except( viewer_windows_exception_handler( GetExceptionInformation() ) )
00168 {
00169 _tprintf( _T("Exception handled.\n") );
00170 }
00171 }
00172 #endif
00173
00174 void LLAppViewerWin32::disableWinErrorReporting()
00175 {
00176 const char win_xp_string[] = "Microsoft Windows XP";
00177 BOOL is_win_xp = ( getOSInfo().getOSString().substr(0, strlen(win_xp_string) ) == win_xp_string );
00178 if( is_win_xp )
00179 {
00180
00181
00182 HINSTANCE fault_rep_dll_handle = LoadLibrary(L"faultrep.dll");
00183 if( fault_rep_dll_handle )
00184 {
00185 pfn_ADDEREXCLUDEDAPPLICATIONA pAddERExcludedApplicationA = (pfn_ADDEREXCLUDEDAPPLICATIONA) GetProcAddress(fault_rep_dll_handle, "AddERExcludedApplicationA");
00186 if( pAddERExcludedApplicationA )
00187 {
00188
00189
00190 const char* executable_name = gDirUtilp->getExecutableFilename().c_str();
00191
00192 if( 0 == pAddERExcludedApplicationA( executable_name ) )
00193 {
00194 U32 error_code = GetLastError();
00195 llinfos << "AddERExcludedApplication() failed with error code " << error_code << llendl;
00196 }
00197 else
00198 {
00199 llinfos << "AddERExcludedApplication() success for " << executable_name << llendl;
00200 }
00201 }
00202 FreeLibrary( fault_rep_dll_handle );
00203 }
00204 }
00205 }
00206
00207 const S32 MAX_CONSOLE_LINES = 500;
00208
00209 void create_console()
00210 {
00211 int h_con_handle;
00212 long l_std_handle;
00213
00214 CONSOLE_SCREEN_BUFFER_INFO coninfo;
00215 FILE *fp;
00216
00217
00218 AllocConsole();
00219
00220
00221 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
00222 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
00223 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
00224
00225
00226 l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
00227 h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
00228 fp = _fdopen( h_con_handle, "w" );
00229 *stdout = *fp;
00230 setvbuf( stdout, NULL, _IONBF, 0 );
00231
00232
00233 l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE);
00234 h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
00235 fp = _fdopen( h_con_handle, "r" );
00236 *stdin = *fp;
00237 setvbuf( stdin, NULL, _IONBF, 0 );
00238
00239
00240 l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE);
00241 h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
00242 fp = _fdopen( h_con_handle, "w" );
00243 *stderr = *fp;
00244 setvbuf( stderr, NULL, _IONBF, 0 );
00245 }
00246
00247 LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) :
00248 mCmdLine(cmd_line)
00249 {
00250 }
00251
00252 LLAppViewerWin32::~LLAppViewerWin32()
00253 {
00254 }
00255
00256 bool LLAppViewerWin32::init()
00257 {
00258
00259
00260
00261
00262
00263
00264 llinfos << "Turning off Windows error reporting." << llendl;
00265 disableWinErrorReporting();
00266
00267 return LLAppViewer::init();
00268 }
00269
00270 bool LLAppViewerWin32::cleanup()
00271 {
00272 bool result = LLAppViewer::cleanup();
00273
00274 gDXHardware.cleanup();
00275
00276 return result;
00277 }
00278
00279 void LLAppViewerWin32::initConsole()
00280 {
00281
00282 create_console();
00283 return LLAppViewer::initConsole();
00284 }
00285
00286 void write_debug_dx(const char* str)
00287 {
00288 LLString value = gDebugInfo["DXInfo"].asString();
00289 value += str;
00290 gDebugInfo["DXInfo"] = value;
00291 }
00292
00293 void write_debug_dx(const std::string& str)
00294 {
00295 write_debug_dx(str.c_str());
00296 }
00297
00298 bool LLAppViewerWin32::initHardwareTest()
00299 {
00300
00301
00302
00303
00304 if (FALSE == gSavedSettings.getBOOL("NoHardwareProbe"))
00305 {
00306 BOOL vram_only = !gSavedSettings.getBOOL("ProbeHardwareOnStartup");
00307
00308
00309
00310 vram_only = TRUE;
00311
00312 LLSplashScreen::update("Detecting hardware...");
00313
00314 LL_DEBUGS("AppInit") << "Attempting to poll DirectX for hardware info" << LL_ENDL;
00315 gDXHardware.setWriteDebugFunc(write_debug_dx);
00316 BOOL probe_ok = gDXHardware.getInfo(vram_only);
00317
00318 if (!probe_ok
00319 && gSavedSettings.getWarning("AboutDirectX9"))
00320 {
00321 LL_WARNS("AppInit") << "DirectX probe failed, alerting user." << LL_ENDL;
00322
00323
00324
00325 std::ostringstream msg;
00326 msg <<
00327 LLAppViewer::instance()->getSecondLifeTitle() << " is unable to detect DirectX 9.0b or greater.\n"
00328 "\n" <<
00329 LLAppViewer::instance()->getSecondLifeTitle() << " uses DirectX to detect hardware and/or\n"
00330 "outdated drivers that can cause stability problems,\n"
00331 "poor performance and crashes. While you can run\n" <<
00332 LLAppViewer::instance()->getSecondLifeTitle() << " without it, we highly recommend running\n"
00333 "with DirectX 9.0b\n"
00334 "\n"
00335 "Do you wish to continue?\n";
00336 S32 button = OSMessageBox(
00337 msg.str().c_str(),
00338 "Warning",
00339 OSMB_YESNO);
00340 if (OSBTN_NO== button)
00341 {
00342 LL_INFOS("AppInit") << "User quitting after failed DirectX 9 detection" << LL_ENDL;
00343 LLWeb::loadURLExternal(DIRECTX_9_URL);
00344 return false;
00345 }
00346 gSavedSettings.setWarning("AboutDirectX9", FALSE);
00347 }
00348 LL_DEBUGS("AppInit") << "Done polling DirectX for hardware info" << LL_ENDL;
00349
00350
00351 gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
00352
00353
00354 std::ostringstream splash_msg;
00355 splash_msg << "Loading " << LLAppViewer::instance()->getSecondLifeTitle() << "...";
00356
00357 LLSplashScreen::update(splash_msg.str().c_str());
00358 }
00359
00360 if (!LLWinDebug::checkExceptionHandler())
00361 {
00362 LL_WARNS("AppInit") << " Someone took over my exception handler (post hardware probe)!" << LL_ENDL;
00363 }
00364
00365 gGLManager.mVRAM = gDXHardware.getVRAM();
00366 LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL;
00367
00368 return true;
00369 }
00370
00371 bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
00372 {
00373 if (!clp.parseCommandLineString(mCmdLine))
00374 {
00375 return false;
00376 }
00377
00378
00379 FL_Locale *locale = NULL;
00380 FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
00381 if (success != 0)
00382 {
00383 if (success >= 2 && locale->lang)
00384 {
00385 LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
00386 if(c)
00387 {
00388 c->setValue(std::string(locale->lang), false);
00389 }
00390 }
00391 FL_FreeLocale(&locale);
00392 }
00393
00394 return true;
00395 }
00396
00397 void LLAppViewerWin32::handleSyncCrashTrace()
00398 {
00399
00400 }
00401
00402 void LLAppViewerWin32::handleCrashReporting()
00403 {
00404
00405 std::string exe_path = gDirUtilp->getAppRODataDir();
00406 exe_path += gDirUtilp->getDirDelimiter();
00407 exe_path += "win_crash_logger.exe";
00408
00409 std::string arg_string = "-user ";
00410 arg_string += gGridName;
00411
00412 switch(getCrashBehavior())
00413 {
00414 case CRASH_BEHAVIOR_ASK:
00415 default:
00416 arg_string += " -dialog ";
00417 _spawnl(_P_NOWAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
00418 break;
00419
00420 case CRASH_BEHAVIOR_ALWAYS_SEND:
00421 _spawnl(_P_NOWAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
00422 break;
00423
00424 case CRASH_BEHAVIOR_NEVER_SEND:
00425 break;
00426 }
00427 }
00428
00429 std::string LLAppViewerWin32::generateSerialNumber()
00430 {
00431 char serial_md5[MD5HEX_STR_SIZE];
00432 serial_md5[0] = 0;
00433
00434 DWORD serial = 0;
00435 DWORD flags = 0;
00436 BOOL success = GetVolumeInformation(
00437 L"C:\\",
00438 NULL,
00439 0,
00440 &serial,
00441 NULL,
00442 &flags,
00443 NULL,
00444 0);
00445 if (success)
00446 {
00447 LLMD5 md5;
00448 md5.update( (unsigned char*)&serial, sizeof(DWORD));
00449 md5.finalize();
00450 md5.hex_digest(serial_md5);
00451 }
00452 else
00453 {
00454 llwarns << "GetVolumeInformation failed" << llendl;
00455 }
00456 return serial_md5;
00457 }