llappviewerwin32.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llappviewerwin32.h"
00035 
00036 #include "llmemtype.h"
00037 
00038 #include "llwindowwin32.cpp" // *FIX: for setting gIconResource.
00039 #include "res/resource.h" // *FIX: for setting gIconResource.
00040 
00041 #include <fcntl.h>              //_O_APPEND
00042 #include <io.h>                 //_open_osfhandle()
00043 #include <errorrep.h>   // for AddERExcludedApplicationA()
00044 #include <process.h>    // _spawnl()
00045 #include <tchar.h>              // For TCHAR support
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     // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
00064         
00065     // Translate the signals/exceptions into cross-platform stuff
00066         // Windows implementation
00067         llinfos << "Entering Windows Exception Handler..." << llendl;
00068 
00069         // Make sure the user sees something to indicate that the app crashed.
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         // Generate a minidump if we can.
00080         // Before we wake the error thread...
00081         // Which will start the crash reporting.
00082         LLWinDebug::generateCrashStacks(exception_infop);
00083         
00084         // Flag status to error, so thread_error starts its work
00085         LLApp::setError();
00086 
00087         // Block in the exception handler until the app has stopped
00088         // This is pretty sketchy, but appears to work just fine
00089         while (!LLApp::isStopped())
00090         {
00091                 ms_sleep(10);
00092         }
00093 
00094         //
00095         // At this point, we always want to exit the app.  There's no graceful
00096         // recovery for an unhandled exception.
00097         // 
00098         // Just kill the process.
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         // *FIX: global
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                 // Run the application main loop
00134         if(!LLApp::isQuitting()) 
00135         {
00136                 viewer_app_ptr->mainLoop();
00137         }
00138 
00139         if (!LLApp::isError())
00140         {
00141                 //
00142                 // We don't want to do cleanup here if the error handler got called -
00143                 // the assumption is that the error handler is responsible for doing
00144                 // app cleanup if there was a problem.
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 // The compiler doesn't like it when you use __try/__except blocks
00155 // in a method that uses object destructors. Go figure.
00156 // This winmain just calls the real winmain inside __try.
00157 // The __except calls our exception filter function. For debugging purposes.
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 );              /* Flawfinder: ignore*/
00178         if( is_win_xp )
00179         {
00180                 // Note: we need to use run-time dynamic linking, because load-time dynamic linking will fail
00181                 // on systems that don't have the library installed (all non-Windows XP systems)
00182                 HINSTANCE fault_rep_dll_handle = LoadLibrary(L"faultrep.dll");          /* Flawfinder: ignore */
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                                 // Strip the path off the name
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         // allocate a console for this app
00218         AllocConsole();
00219 
00220         // set the screen buffer to be big enough to let us scroll text
00221         GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
00222         coninfo.dwSize.Y = MAX_CONSOLE_LINES;
00223         SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
00224 
00225         // redirect unbuffered STDOUT to the console
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         // redirect unbuffered STDIN to the console
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         // redirect unbuffered STDERR to the console
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         // Platform specific initialization.
00259         
00260         // Turn off Windows XP Error Reporting
00261         // (Don't send our data to Microsoft--at least until we are Logo approved and have a way
00262         // of getting the data back from them.)
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         // pop up debug console
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         // Do driver verification and initialization based on DirectX
00302         // hardware polling and driver versions
00303         //
00304         if (FALSE == gSavedSettings.getBOOL("NoHardwareProbe"))
00305         {
00306                 BOOL vram_only = !gSavedSettings.getBOOL("ProbeHardwareOnStartup");
00307 
00308                 // per DEV-11631 - disable hardware probing for everything
00309                 // but vram.
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                         // Warn them that runnin without DirectX 9 will
00324                         // not allow us to tell them about driver issues
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                 // Only probe once after installation
00351                 gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
00352 
00353                 // Disable so debugger can work
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         // Find the system language.
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) // confident!
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         // do nothing
00400 }
00401 
00402 void LLAppViewerWin32::handleCrashReporting()
00403 {
00404         // Windows only behaivor. Spawn win crash reporter.
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];               // Flawfinder: ignore
00432         serial_md5[0] = 0;
00433 
00434         DWORD serial = 0;
00435         DWORD flags = 0;
00436         BOOL success = GetVolumeInformation(
00437                         L"C:\\",
00438                         NULL,           // volume name buffer
00439                         0,                      // volume name buffer size
00440                         &serial,        // volume serial
00441                         NULL,           // max component length
00442                         &flags,         // file system flags
00443                         NULL,           // file system name buffer
00444                         0);                     // file system name buffer size
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 }

Generated on Fri May 16 08:33:15 2008 for SecondLife by  doxygen 1.5.5