所有Windows图形应用程序都是拥有相同的入口点函数WinMain,因此第二人生的程序也不例外。下面先来看看这个函数的代码,如下:
//蔡军生 2007/12/28 QQ:9073204 深圳
#001 int APIENTRY WinMain(HINSTANCE hInstance,
#002 HINSTANCE hPrevInstance,
#003 LPSTR lpCmdLine,
#004 int nCmdShow)
#005 {
#006 LLMemType mt1(LLMemType::MTYPE_STARTUP);
这行代码主要作用就是声明跟踪内存分配的类型。LLMemType类统计当前使用内存大小,并且可以输出内存的类型信息。
#007
#008 // *FIX: global
#009 gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
这行代码主要获取资源里的ICON图标句柄。
#010
#011 // In Win32, we need to generate argc and argv ourselves...
#012 // Note: GetCommandLine() returns a potentially return a LPTSTR
#013 // which can resolve to a LPWSTR (unicode string).
#014 // (That‘s why it‘s different from lpCmdLine which is a LPSTR.)
#015 // We don‘t currently do unicode, so call the non-unicode version
#016 // directly.
#017 LPSTR cmd_line_including_exe_name = GetCommandLineA();
这里是获取命令行参数,在Windows API一日一练里已经介绍过,如果不懂可以参考它。
#018
#019 const S32 MAX_ARGS = 100;
#020 int argc = 0;
#021 char* argv[MAX_ARGS]; /* Flawfinder: ignore */
#022
#023 fill_args(argc, argv, MAX_ARGS, cmd_line_including_exe_name);
上面这段代码是分析输入的命令行参数。
#024
#025 LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32();
这行代码开始创建Windows窗口管理程序,也就是第二人生的管理类。
#026
#027 // *FIX:Mani This method is poorly named, since the exception
#028 // is now handled by LLApp.
#029 bool ok = LLWinDebug::setupExceptionHandler();
这行代码实现了加载dbghelp.dll的功能,主要为了生成程序运行出错信息报表,可以精确地定位在那个模块里出错,并且把当时的环境参数全部生成报表,上传给第二人生开发厂家,以便改正这个出错的原因。
#030
#031 // Actually here‘s the exception setup.
#032 LPTOP_LEVEL_EXCEPTION_FILTER prev_filter;
#033 prev_filter = SetUnhandledExceptionFilter(viewer_windows_exception_handler);
这里设置了系统异常出错处理函数,当应用程序产生非法出错时,就会调用这个函数来生成报表。
#034 if (!prev_filter)
#035 {
#036 llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with NULL!" << llendl;
#037 ok = FALSE;
#038 }
#039 if (prev_filter != LLWinDebug::handleException)
#040 {
#041 llwarns << "Our exception handler (" << (void *)LLWinDebug::handleException << ") replaced with " << prev_filter << "!" << llendl;
#042 ok = FALSE;
#043 }
上面这段代码主要判断是否设置Windows异常处理成功。
#044
#045 viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
这行代码保存异常处理函数。
#046
#047 ok = viewer_app_ptr->tempStoreCommandOptions(argc, argv);
#048 if(!ok)
#049 {
#050 llwarns << "Unable to parse command line." << llendl;
#051 return -1;
#052 }
#053
上面保存命令行参数。
#054 ok = viewer_app_ptr->init();
#055 if(!ok)
#056 {
#057 llwarns << "Application init failed." << llendl;
#058 return -1;
#059 }
#060
调用函数init来初始化整个应用程序,比如创建线程,初始化OpenGL等等,在这个函数里实现大部份功能的初始化。
#061 // Run the application main loop
#062 if(!LLApp::isQuitting())
#063 {
#064 viewer_app_ptr->mainLoop();
#065 }
上面第62行检查否有退出应用程序的可能。
第64行就进入了Windows应用程序的消息处理函数,在这个函数里实现主窗口的消息处理,还实现空闲处理,键盘输入处理,接收到网络命令,以及OpenGL渲染。
#066
#067 if (!LLApp::isError())
#068 {
#069 //
#070 // We don‘t want to do cleanup here if the error handler got called -
#071 // the assumption is that the error handler is responsible for doing
#072 // app cleanup if there was a problem.
#073 //
#074 viewer_app_ptr->cleanup();
#075 }
#076 delete viewer_app_ptr;
#077 viewer_app_ptr = NULL;
#078 return 0;
#079 }
上面这段代码,检查是否出错退出,如果出错就清空所有分配的资源。最后删除应用程序管理类。
通过这个函数的学习,会发现第二人生的代码写得比较强悍的,不但出错的处理面面具到,还具备了运行时调试信息输出,强大的LOG系统功能。通过这个函数应学会怎么样添加处理系统异常出错的方法,调试发行版的程序方法,怎么生成具体的报表发送给软件开发厂商的实现。
总结一下,这里运行的流程:
1、 调用WIN API函数GetCommandLineA来获取命令行参数。
2、 调用fill_args函数分析命令行参数。
3、 调用函数LLWinDebug::setupExceptionHandler来加载调试库DebugHlp.dll。
4、 调用函数SetUnhandledExceptionFilter来设置新异常处理。
5、 调函数viewer_app_ptr->init来实始化管理类所有初始化工作。
6、 调用函数viewer_app_ptr->mainLoop进入Windows的消息循环处理。
7、 删除所有分配的资源。