目录
1 MainGui.cpp源代码
2 int main()函数分析
3 编译运行截图
FreeCADMain项目下的MainGui.cpp
1 MainGui.cpp源代码
int main( int argc, char ** argv )
{
#if defined (FC_OS_LINUX) || defined(FC_OS_BSD)setlocale(LC_ALL, ""); // use native environment settings// Make sure to setup the Qt locale system before setting LANG and LC_ALL to C.// which is needed to use the system locale settings.(void)QLocale::system();// See https://forum.freecad.org/viewtopic.php?f=18&t=20600// See Gui::Application::runApplication()putenv("LC_NUMERIC=C");putenv("PYTHONPATH=");
#elif defined(FC_OS_MACOSX)(void)QLocale::system();putenv("PYTHONPATH=");
#elif defined(__MINGW32__)const char* mingw_prefix = getenv("MINGW_PREFIX");const char* py_home = getenv("PYTHONHOME");if (!py_home && mingw_prefix)_putenv_s("PYTHONHOME", mingw_prefix);
#else_putenv("PYTHONPATH=");// https://forum.freecad.org/viewtopic.php?f=4&t=18288// https://forum.freecad.org/viewtopic.php?f=3&t=20515const char* fc_py_home = getenv("FC_PYTHONHOME");if (fc_py_home)_putenv_s("PYTHONHOME", fc_py_home);else_putenv("PYTHONHOME=");
#endif#if defined (FC_OS_WIN32)// we need to force Coin not to use Freetype in order to find installed fonts on Windows// see https://forum.freecad.org/viewtopic.php?p=485142#p485016_putenv("COIN_FORCE_FREETYPE_OFF=1");int argc_ = argc;QVector<QByteArray> data;QVector<char *> argv_;// get the command line arguments as unicode string{QCoreApplication app(argc, argv);QStringList args = app.arguments();for (QStringList::iterator it = args.begin(); it != args.end(); ++it) {data.push_back(it->toUtf8());argv_.push_back(data.back().data());}argv_.push_back(0); // 0-terminated string}
#endif// Name and Version of the ApplicationApp::Application::Config()["ExeName"] = "FreeCAD";App::Application::Config()["ExeVendor"] = "FreeCAD";App::Application::Config()["AppDataSkipVendor"] = "true";App::Application::Config()["MaintainerUrl"] = "http://www.freecad.org/wiki/Main_Page";// set the banner (for logging and console)App::Application::Config()["CopyrightInfo"] = sBanner;App::Application::Config()["AppIcon"] = "freecad";App::Application::Config()["SplashScreen"] = "freecadsplash";App::Application::Config()["AboutImage"] = "freecadabout";App::Application::Config()["StartWorkbench"] = "StartWorkbench";//App::Application::Config()["HiddenDockWindow"] = "Property editor";App::Application::Config()["SplashAlignment" ] = "Bottom|Left";App::Application::Config()["SplashTextColor" ] = "#8aadf4"; // light blueApp::Application::Config()["SplashInfoColor" ] = "#8aadf4"; // light blue App::Application::Config()["SplashInfoPosition" ] = "6,75";QGuiApplication::setDesktopFileName(QStringLiteral("org.freecad.FreeCAD.desktop"));try {// Init phase ===========================================================// sets the default run mode for FC, starts with gui if not overridden in InitConfig...App::Application::Config()["RunMode"] = "Gui";App::Application::Config()["Console"] = "0";App::Application::Config()["LoggingConsole"] = "1";// Inits the Application
#if defined (FC_OS_WIN32)App::Application::init(argc_, argv_.data());
#elseApp::Application::init(argc, argv);
#endif
#if defined(_MSC_VER)// create a dump file when the application crashesstd::string dmpfile = App::Application::getUserAppDataDir();dmpfile += "crash.dmp";InitMiniDumpWriter(dmpfile);
#endifstd::map<std::string, std::string>::iterator it = App::Application::Config().find("NavigationStyle");if (it != App::Application::Config().end()) {ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");// if not already defined do it now (for the very first start)std::string style = hGrp->GetASCII("NavigationStyle", it->second.c_str());hGrp->SetASCII("NavigationStyle", style.c_str());}Gui::Application::initApplication();// Only if 'RunMode' is set to 'Gui' do the replacementif (App::Application::Config()["RunMode"] == "Gui")Base::Interpreter().replaceStdOutput();}catch (const Base::UnknownProgramOption& e) {QApplication app(argc,argv);QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());QString msg = QString::fromLatin1(e.what());QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");QMessageBox::critical(nullptr, appName, s);exit(1);}catch (const Base::ProgramInformation& e) {QApplication app(argc,argv);QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());QString msg = QString::fromUtf8(e.what());QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");QMessageBox msgBox;msgBox.setIcon(QMessageBox::Information);msgBox.setWindowTitle(appName);msgBox.setDetailedText(msg);msgBox.setText(s);msgBox.exec();exit(0);}catch (const Base::Exception& e) {// Popup an own dialog box instead of that one of WindowsQApplication app(argc,argv);QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());QString msg;msg = QObject::tr("While initializing %1 the following exception occurred: '%2'\n\n""Python is searching for its files in the following directories:\n%3\n\n""Python version information:\n%4\n").arg(appName, QString::fromUtf8(e.what()),QString::fromUtf8(Py_EncodeLocale(Py_GetPath(),nullptr)), QString::fromLatin1(Py_GetVersion()));const char* pythonhome = getenv("PYTHONHOME");if (pythonhome) {msg += QObject::tr("\nThe environment variable PYTHONHOME is set to '%1'.").arg(QString::fromUtf8(pythonhome));msg += QObject::tr("\nSetting this environment variable might cause Python to fail. ""Please contact your administrator to unset it on your system.\n\n");} else {msg += QObject::tr("\nPlease contact the application's support team for more information.\n\n");}QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg);exit(100);}catch (...) {// Popup an own dialog box instead of that one of WindowsQApplication app(argc,argv);QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());QString msg = QObject::tr("Unknown runtime error occurred while initializing %1.\n\n""Please contact the application's support team for more information.\n\n").arg(appName);QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg);exit(101);}// Run phase ===========================================================Base::RedirectStdOutput stdcout;Base::RedirectStdLog stdclog;Base::RedirectStdError stdcerr;std::streambuf* oldcout = std::cout.rdbuf(&stdcout);std::streambuf* oldclog = std::clog.rdbuf(&stdclog);std::streambuf* oldcerr = std::cerr.rdbuf(&stdcerr);try {// if console option is set then run in cmd modeif (App::Application::Config()["Console"] == "1")App::Application::runApplication();if (App::Application::Config()["RunMode"] == "Gui" ||App::Application::Config()["RunMode"] == "Internal")Gui::Application::runApplication();elseApp::Application::runApplication();}catch (const Base::SystemExitException& e) {exit(e.getExitCode());}catch (const Base::Exception& e) {e.ReportException();exit(1);}catch (const std::exception& e) {Base::Console().Error("Application unexpectedly terminated: %s\n", e.what());exit(1);}catch (...) {Base::Console().Error("Application unexpectedly terminated\n");exit(1);}std::cout.rdbuf(oldcout);std::clog.rdbuf(oldclog);std::cerr.rdbuf(oldcerr);// Destruction phase ===========================================================Base::Console().Log("%s terminating...\n",App::Application::Config()["ExeName"].c_str());// cleans upApp::Application::destruct();Base::Console().Log("%s completely terminated\n",App::Application::Config()["ExeName"].c_str());return 0;
}
2 int main()函数分析
int main( int argc, char ** argv )
{ // 如果操作系统是Linux或BSD,则设置本地化环境为当前环境设置
#if defined (FC_OS_LINUX) || defined(FC_OS_BSD) setlocale(LC_ALL, ""); // use native environment settings // 在将LANG和LC_ALL设置为C之前,确保设置了Qt的本地化系统, // 这样才能使用系统本地化设置。 // See https://forum.freecad.org/viewtopic.php?f=18&t=20600 // See Gui::Application::runApplication() putenv("LC_NUMERIC=C"); putenv("PYTHONPATH=");
#elif defined(FC_OS_MACOSX) // 对于Mac OS X,同样设置本地化系统,并且设置PYTHONPATH环境变量为空 (void)QLocale::system(); putenv("PYTHONPATH=");
#elif defined(__MINGW32__) // 对于MinGW,获取MINGW_PREFIX环境变量,并获取PYTHONHOME环境变量, // 如果PYTHONHOME未设置且MINGW_PREFIX存在,则将PYTHONHOME设置为MINGW_PREFIX const char* mingw_prefix = getenv("MINGW_PREFIX"); const char* py_home = getenv("PYTHONHOME"); if (!py_home && mingw_prefix) _putenv_s("PYTHONHOME", mingw_prefix);
#else // 对于其他操作系统,将PYTHONPATH环境变量设置为空,并获取FC_PYTHONHOME环境变量, // 如果存在,则将PYTHONHOME设置为FC_PYTHONHOME;否则,将PYTHONHOME环境变量设置为空 _putenv("PYTHONPATH="); // https://forum.freecad.org/viewtopic.php?f=4&t=18288 // https://forum.freecad.org/viewtopic.php?f=3&t=20515 const char*fc_py_home = getenv("FC_PYTHONHOME"); if (fc_py_home) _putenv_s("PYTHONHOME",fc_py_home); else _putenv("PYTHONHOME=");
#endif #if defined (FC_OS_WIN32) // 我们需要强制Coin不使用Freetype来找到Windows上已安装的字体, // 见 https://forum.freecad.org/viewtopic.php?p=485142#p485016 // 设置COIN_FORCE_FREETYPE_OFF环境变量为1,强制Coin不使用Freetype _putenv("COIN_FORCE_FREETYPE_OFF=1"); // 对于Windows,我们创建一个新的命令行参数数组,并将其转换为unicode字符串格式 int argc_ = argc; QVector<QByteArray> data; QVector<char *> argv_; // 获取命令行参数并将其转换为unicode字符串格式 { QCoreApplication app(argc, argv); // 使用QCoreApplication来获取命令行参数列表 QStringList args = app.arguments(); // 获取命令行参数列表(包括程序名称) for (QStringList::iterator it = args.begin(); it != args.end(); ++it) { // 遍历参数列表并转换为utf-8格式的字节数组并存入data中 data.push_back(it->toUtf8()); // 转换参数为utf-8格式的字节数组并存入data中 argv_.push_back(data.back().data()); argv_.push_back(0); // 0-terminated string}
#endif// 应用程序的名称和版本 App::Application::Config()["ExeName"] = "FreeCAD"; // 应用程序名称 App::Application::Config()["ExeVendor"] = "FreeCAD"; // 应用程序供应商 App::Application::Config()["AppDataSkipVendor"] = "true"; // 跳过应用程序数据供应商 App::Application::Config()["MaintainerUrl"] = "http://www.freecad.org/wiki/Main_Page"; // 维护者URL // 设置横幅(用于日志记录和控制台) App::Application::Config()["CopyrightInfo"] = sBanner; // 版权信息 App::Application::Config()["AppIcon"] = "freecad"; // 应用程序图标 App::Application::Config()["SplashScreen"] = "freecadsplash"; // 启动画面 App::Application::Config()["AboutImage"] = "freecadabout"; // 关于图像 App::Application::Config()["StartWorkbench"] = "StartWorkbench"; // 启动工作台
//App::Application::Config()["HiddenDockWindow"] = "Property editor"; // 隐藏停靠窗口 App::Application::Config()["SplashAlignment" ] = "Bottom|Left"; // 启动画面对齐方式 App::Application::Config()["SplashTextColor" ] = "#8aadf4"; // 启动画面文本颜色(浅蓝色) App::Application::Config()["SplashInfoColor" ] = "#8aadf4"; // 启动画面信息颜色(浅蓝色) App::Application::Config()["SplashInfoPosition" ] = "6,75"; // 启动画面信息位置 QGuiApplication::setDesktopFileName(QStringLiteral("org.freecad.FreeCAD.desktop")); // 设置桌面文件名 try { // 初始化阶段 =========================================================== // 设置FC的默认运行模式,如果没有在InitConfig中覆盖,则从GUI开始 App::Application::Config()["RunMode"] = "Gui"; // 运行模式(GUI) App::Application::Config()["Console"] = "0"; // 控制台模式(0-无,1-有) App::Application::Config()["LoggingConsole"] = "1"; // 日志记录到控制台(1-是,0-否) // 初始化应用程序
#if defined (FC_OS_WIN32) App::Application::init(argc_, argv_.data()); // 在Windows平台上初始化应用程序
#else App::Application::init(argc, argv); // 在其他平台上初始化应用程序
#endif
#if defined(_MSC_VER) // 当应用程序崩溃时创建一个转储文件 std::string dmpfile = App::Application::getUserAppDataDir(); // 获取用户应用程序数据目录 dmpfile += "crash.dmp"; // 添加文件后缀名 InitMiniDumpWriter(dmpfile); // 初始化MiniDumpWriter,用于生成.dmp文件,有助于程序崩溃后的调试
#endif
#if defined(_MSC_VER) // 当应用程序崩溃时创建一个转储文件 // create a dump file when the application crashes std::string dmpfile = App::Application::getUserAppDataDir(); dmpfile += "crash.dmp"; InitMiniDumpWriter(dmpfile);
#endif // 查找配置文件中的 "NavigationStyle" 键值对 std::map<std::string, std::string>::iterator it = App::Application::Config().find("NavigationStyle"); if (it != App::Application::Config().end()) { // 通过路径获取用户参数组,并设置 "NavigationStyle" 的值 ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); // 如果未定义,则立即定义(对于第一次启动) std::string style = hGrp->GetASCII("NavigationStyle", it->second.c_str()); hGrp->SetASCII("NavigationStyle", style.c_str()); } // 初始化应用程序 Gui::Application::initApplication(); // 如果 'RunMode' 被设置为 'Gui',则替换标准输出 // Only if 'RunMode' is set to 'Gui' do the replacement if (App::Application::Config()["RunMode"] == "Gui") Base::Interpreter().replaceStdOutput(); } catch (const Base::UnknownProgramOption& e) { // 捕获异常,用于处理未知的程序选项问题 QApplication app(argc,argv); QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str()); QString msg = QString::fromLatin1(e.what()); QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>"); QMessageBox::critical(nullptr, appName, s); exit(1); } catch (const Base::ProgramInformation& e) { // 捕获异常,用于处理程序信息问题 QApplication app(argc,argv); QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str()); QString msg = QString::fromUtf8(e.what()); QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>"); QMessageBox msgBox; msgBox.setIcon(QMessageBox::Information); msgBox.setWindowTitle(appName); msgBox.setDetailedText(msg); msgBox.setText(s); msgBox.exec(); exit(0); }catch (const Base::Exception& e) { // 捕获Base::Exception类型的异常 // 弹出自定义的对话框,而不是Windows的对话框 // Popup an own dialog box instead of that one of Windows QApplication app(argc,argv); QString appName = QString::fromLatin1(App::Application::Config() ["ExeName"].c_str()); QString msg; // 使用占位符构建错误消息,其中%1表示应用名称,%2表示异常信息,%3表示Python正在搜索的目录,%4表示Python版本信息 msg = QObject::tr("While initializing %1 the following exception occurred: '%2'\n\n" "Python is searching for its files in the following directories:\n%3\n\n" "Python version information:\n%4\n") .arg(appName, QString::fromUtf8(e.what()), QString::fromUtf8(Py_EncodeLocale(Py_GetPath(),nullptr)), QString::fromLatin1(Py_GetVersion())); const char* pythonhome = getenv("PYTHONHOME"); if (pythonhome) { // 如果环境变量PYTHONHOME被设置,则添加相应的错误消息 msg += QObject::tr("\nThe environment variable PYTHONHOME is set to '%1'.") .arg(QString::fromUtf8(pythonhome)); msg += QObject::tr("\nSetting this environment variable might cause Python to fail. " "Please contact your administrator to unset it on your system.\n\n"); } else { // 如果环境变量PYTHONHOME没有被设置,则添加相应的错误消息 msg += QObject::tr("\nPlease contact the application's support team for more information.\n\n"); } // 显示错误消息的对话框,标题为应用名称,内容为错误消息,然后退出程序并返回错误码100 QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg); exit(100); }
// 捕获任何异常,用于处理未知的运行时错误
catch (...) { // 弹出自定义的对话框,而不是Windows的系统对话框 // Popup an own dialog box instead of that one of Windows QApplication app(argc,argv); QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str()); QString msg = QObject::tr("Unknown runtime error occurred while initializing %1.\n\n" "Please contact the application's support team for more information.\n\n").arg(appName); // 显示错误消息的对话框,标题为应用名称,内容为错误消息,然后退出程序并返回错误码101 QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg); exit(101);
} // 运行阶段 ===========================================================
// 重定向标准输出流、标准日志流和标准错误流 Base::RedirectStdOutput stdcout; Base::RedirectStdLog stdclog; Base::RedirectStdError stdcerr;
// 保存旧的cout、clog和cerr缓冲区指针,用于后续恢复 std::streambuf* oldcout = std::cout.rdbuf(&stdcout); std::streambuf* oldclog = std::clog.rdbuf(&stdclog); std::streambuf* oldcerr = std::cerr.rdbuf(&stdcerr); try { // 如果设置了控制台选项,则在命令行模式下运行应用程序 // if console option is set then run in cmd mode if (App::Application::Config()["Console"] == "1") App::Application::runApplication(); // 如果运行模式为Gui或Internal,则在GUI模式下运行应用程序 if (App::Application::Config()["RunMode"] == "Gui" || App::Application::Config()["RunMode"] == "Internal") Gui::Application::runApplication(); // 否则,在默认模式下运行应用程序 else App::Application::runApplication();
}
// 捕获Base::SystemExitException异常,根据其退出码退出程序
catch (const Base::SystemExitException& e) { exit(e.getExitCode());
}
// 捕获Base::Exception异常,报告异常并退出程序,返回状态码1
catch (const Base::Exception& e) { e.ReportException(); exit(1);
}
// 捕获std::exception异常,输出错误信息并退出程序,返回状态码1
catch (const std::exception& e) { Base::Console().Error("Application unexpectedly terminated: %s\n", e.what()); exit(1);
}
// 捕获其他所有异常,输出错误信息并退出程序,返回状态码1
catch (...) { Base::Console().Error("Application unexpectedly terminated\n"); exit(1);
} // 恢复旧的cout、clog和cerr缓冲区指针,以便后续正常输出流控制恢复正常状态 std::cout.rdbuf(oldcout); std::clog.rdbuf(oldclog); std::cerr.rdbuf(oldcerr);
// 销毁阶段 ===========================================================
// 记录应用程序终止信息 Base::Console().Log("%s terminating...\n",App::Application::Config() ["ExeName"].c_str()); // 清理资源
// cleans up App::Application::destruct(); // 记录应用程序完全终止信息 Base::Console().Log("%s completely terminated\n",App::Application::Config() ["ExeName"].c_str()); // 返回0,表示程序正常结束 return 0;
}