- 版本
NX9+VS2012
- 用户出口(入口)介绍
这段内容是从书上抄的
用户出口(User Exit)是NXOpen中的一个重要概念。NX在运行过程中某些特定的位置存在规定的出口,当进程执行到这些出口时,NX会自动检查用户是否在此处已定义了
指向内部程序位置的环境变量;若没有定义,则以NX默认的方式继续运行下去;若已定义,则从该处自动运行用户定制的应用程序。利用不同的User Exit,可使用户定制
的应用程序在NX运行到特定点时被自动执行。每个User Exit都有唯一的出口名称,以便用户在子程序中调用,不同的User Exit使用不同的出口函数,最常用的User Exit是
ufsta()与ufusr(),ufsta()是NX菜单启动时的User Exit,ufusr()是直接激活的User Exit。通常情况下,User Exit函数的参数和返回值都相同,User Exit函数的定义如下:
void entry_point(char *parm, int *returnCode, int rlen);
其中parm和returnCode是输出参数,rlen是指参数parm的长度,由NX系统自动处理。
- 官方文档上的说明
- 常用的两个入口函数例子
- ufusr()
官方有一个example例子,我们编译执行去看一下
/*=========================================================================== Copyright (c) 1998 Unigraphics Solutions Corporation Unpublished - All rights reserved ===========================================================================*/ /* ************************************************************************ * * * This is a sample C program written for Internal User Function. * * Its intent is a small, prewritten program so users can test * * Internal UFUN on their system to make sure it works. * * * * param - Parameters - Input, But Not Used * * retcod - Return Code - Output * * param_len - Length of 'param' argument - Input * * * * * ************************************************************************/ #include <stdio.h> #include <uf_defs.h> #include <uf.h> #include <uf_ui.h> #include <uf_cfi.h> #include <uf_curve.h> #include <uf_obj.h> #include <uf_part.h> #include <uf_assem.h> #include <uf_cfi.h> static void report_error( int error_code, char *msg_text, char *part_name ); #define WAIT 1 #define PART 2 extern void ufusr( char *param, int *retcod, int param_len ) { static char title[] = "CHOOSE OPTION"; static char menu[6][37+1] = { "POINT", "LINE", "ARC", "DELETE LAST ENTITY", "CHANGE ARC MODE", "EXIT PROGRAM" }; static char mdmenu[2][37+1] = { "PARTIAL ARC", "FULL CIRCLE" }; static char linmsg[2][18] = { "CHOOSE LINE START", "CHOOSE LINE END" }; static char arcmsg[] = "CHOOSE POINT #"; static char prtnam[MAX_FSPEC_BUFSIZE] = "blank"; int choice; /* User Choice */ int defalt[2]; /* Default Point Selection Type*/ tag_t entid = 0; /* Entity Identifer */ int idum; /* Dummy Integer Variable */ int mode = 1; /* Arc Creation Mode */ double point1[3]; /* Point Data Variable */ double point2[3]; /* Point Data Variable */ double point3[3]; /* Point Data Variable */ int status; /* Status */ int nopart; /* No active part flag */ int pos_returned; /* Pos returned flag from menu */ int rejected = 0; /* Reject flag from menu */ /* */ tag_t part_tag; /* Part Tag of Part */ UF_PART_load_status_t /* */ load_status; /* Structure to hold any */ /* errors when loading part */ int num_parts; /* Number of parts loaded */ UF_initialize(); /* Check For An Active Part */ part_tag = UF_ASSEM_ask_work_part(); if ( part_tag == NULL_TAG ) { /* Ask For A Part To Retrieve or Create */ nopart = 1; while (nopart) { choice = uc1600("Retrieve/Create part*Enter name", prtnam, &idum); if (choice < 3) { return; } nopart=((choice != 1) && (choice != 4) && (prtnam[0] != 0)) ? 0 : 1; /* Check if the named part already exists on disk */ status = uc4560(prtnam, PART); if ( status == 0 ) { /* Retrieve specified part */ status = UF_PART_open( prtnam, &part_tag, &load_status ); nopart = 0; num_parts = load_status.n_parts; if ( status != 0 ) { report_error( status, "retrieving part", prtnam ); nopart = 1; } if ( num_parts > 0 ) { int indx = 0; while ( indx < num_parts ) { report_error( load_status.statuses[indx], "retrieving part", load_status.file_names[indx] ); indx++; } UF_free_string_array( num_parts, load_status.file_names ); UF_free( load_status.statuses ); nopart = 1; } } else if ( status == 1 ) { /* Create specified part */ status = UF_PART_new(prtnam, UF_PART_ENGLISH, &part_tag ); report_error( status, "creating part", prtnam ); if ( status == 0 ) nopart = 0; } else { report_error( status, "checking part", prtnam ); } } } /* We Now Have An Active Part */ /* Get Next Action Choice (This Section Loops) */ while (1) { choice = uc1603(title, 0, menu, 6); /* Should always cancel out of the ufun dialog when the * user selects cancel or back */ if (choice == 1 || choice == 2) { UF_terminate(); } choice += -4; defalt[0] = 0; switch (choice) { case 1: /* Create Points */ choice = uc1616("CREATE POINT", defalt, 0, point1); while (choice > 4) { UF_CURVE_create_point ( point1 , &entid ); choice = uc1616("CREATE POINT", defalt, 0, point1); } break; case 2: /* Create Lines */ choice = 5; while (choice > 4) { UF_CURVE_line_t line_coords; choice = uc1616(linmsg[0], defalt, 0, line_coords.start_point ); if (choice > 4) { choice = uc1616(linmsg[1], defalt, 0, line_coords.end_point ); if (choice > 4) UF_CURVE_create_line ( &line_coords , &entid ); if (choice == 1) choice = 5; } } break; case 3: /* Create Arcs/Circles */ pos_returned = 1; while (pos_returned) { arcmsg[13] = '1'; choice = uc1616(arcmsg, defalt, 0, point1); pos_returned = (choice > 4) ? 1 : 0; if (choice > 4) do { arcmsg[13] = '2'; choice = uc1616(arcmsg, defalt, 0, point2); if (choice > 4) { arcmsg[13] = '3'; choice = uc1616(arcmsg, defalt, 0, point3); rejected = (choice == 1) ? 1 : 0; if (choice > 4) FTN(uf5063)(&mode,point1,point2,point3,&entid); } else /* check work */ { rejected = (choice == 1) ? 0 : 1; pos_returned = (choice == 1) ? 1 : 0; } } while (rejected); } break; case 4: /* Delete Last Entity Created */ if (entid != 0) UF_OBJ_delete_object(entid); entid = 0; break; case 5: /* Change Arc Mode */ choice = uc1603("CHOOSE ARC MODE", mode, mdmenu, 2); if (choice > 4) mode = choice - 4; break; default: UF_terminate ( ); return; } } } /*----------------------------------------------------------------------------*/ static void report_error( int error_code, char *msg_text, char *part_name ) { if ( error_code != 0 ) { char error_message[133]; char local_string[300]; UF_get_fail_message( error_code, error_message ); sprintf(local_string,"Error %d %s: %s - %s", error_code, msg_text, part_name, error_message ); uc1601( local_string, WAIT ); } }
我们二次开发最常用的入口函数就是ufusr()
执行ufusr有两种方式,
1.是直接挂到菜单栏上,从菜单点击下载。
2.是ctrl+u去执行dll
在用向导创建NX项目的时候,选择ufusr()
ctrl+u方式调用
源代码
//NX9_NXOpenCPP_Wizard8 // Mandatory UF Includes #include <uf.h> #include <uf_object_types.h> // Internal Includes #include <NXOpen/ListingWindow.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/UI.hxx> // Internal+External Includes #include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include <NXOpen/Assemblies_ComponentAssembly.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/BodyCollection.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Line.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/NXObject.hxx> #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include <NXOpen/Session.hxx> //头文件 #include <uf.h> #include <uf_ui.h> // Std C++ Includes #include <iostream> #include <sstream> using namespace NXOpen; using std::string; using std::exception; using std::stringstream; using std::endl; using std::cout; using std::cerr; //------------------------------------------------------------------------------ // NXOpen c++ test class //------------------------------------------------------------------------------ class MyClass { // class members public: static Session *theSession; static UI *theUI; MyClass(); ~MyClass(); void do_it(); void print(const NXString &); void print(const string &); void print(const char*); private: Part *workPart, *displayPart; NXMessageBox *mb; ListingWindow *lw; LogFile *lf; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(MyClass::theSession) = NULL; UI *(MyClass::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ MyClass::MyClass() { // Initialize the NX Open C++ API environment MyClass::theSession = NXOpen::Session::GetSession(); MyClass::theUI = UI::GetUI(); mb = theUI->NXMessageBox(); lw = theSession->ListingWindow(); lf = theSession->LogFile(); workPart = theSession->Parts()->Work(); displayPart = theSession->Parts()->Display(); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ MyClass::~MyClass() { } //------------------------------------------------------------------------------ // Print string to listing window or stdout //------------------------------------------------------------------------------ void MyClass::print(const NXString &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const string &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const char * msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } //------------------------------------------------------------------------------ // Do something //------------------------------------------------------------------------------ void MyClass::do_it() { // TODO: add your code here UF_initialize(); uc1601("SB", 1); UF_terminate(); } //------------------------------------------------------------------------------ // Entry point(s) for unmanaged internal NXOpen C/C++ programs //------------------------------------------------------------------------------ // Explicit Execution extern "C" DllExport void ufusr( char *parm, int *returnCode, int rlen ) { try { // Create NXOpen C++ class instance MyClass *theMyClass; theMyClass = new MyClass(); theMyClass->do_it(); delete theMyClass; } catch (const NXException& e1) { UI::GetUI()->NXMessageBox()->Show("NXException", NXOpen::NXMessageBox::DialogTypeError, e1.Message()); } catch (const exception& e2) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, e2.what()); } catch (...) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, "Unknown Exception."); } } //------------------------------------------------------------------------------ // Unload Handler //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { return (int)NXOpen::Session::LibraryUnloadOptionImmediately; }
演示
挂菜单按钮调用,传button id参数
源代码
//NX9_NXOpenCPP_Wizard8 // Mandatory UF Includes #include <uf.h> #include <uf_object_types.h> // Internal Includes #include <NXOpen/ListingWindow.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/UI.hxx> // Internal+External Includes #include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include <NXOpen/Assemblies_ComponentAssembly.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/BodyCollection.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Line.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/NXObject.hxx> #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include <NXOpen/Session.hxx> //头文件 #include <uf.h> #include <uf_ui.h> // Std C++ Includes #include <iostream> #include <sstream> using namespace NXOpen; using std::string; using std::exception; using std::stringstream; using std::endl; using std::cout; using std::cerr; //------------------------------------------------------------------------------ // NXOpen c++ test class //------------------------------------------------------------------------------ class MyClass { // class members public: static Session *theSession; static UI *theUI; MyClass(); ~MyClass(); void do_it(); void print(const NXString &); void print(const string &); void print(const char*); private: Part *workPart, *displayPart; NXMessageBox *mb; ListingWindow *lw; LogFile *lf; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(MyClass::theSession) = NULL; UI *(MyClass::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ MyClass::MyClass() { // Initialize the NX Open C++ API environment MyClass::theSession = NXOpen::Session::GetSession(); MyClass::theUI = UI::GetUI(); mb = theUI->NXMessageBox(); lw = theSession->ListingWindow(); lf = theSession->LogFile(); workPart = theSession->Parts()->Work(); displayPart = theSession->Parts()->Display(); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ MyClass::~MyClass() { } //------------------------------------------------------------------------------ // Print string to listing window or stdout //------------------------------------------------------------------------------ void MyClass::print(const NXString &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const string &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const char * msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } //------------------------------------------------------------------------------ // Do something //------------------------------------------------------------------------------ void MyClass::do_it() { // TODO: add your code here } //------------------------------------------------------------------------------ // Entry point(s) for unmanaged internal NXOpen C/C++ programs //------------------------------------------------------------------------------ // Explicit Execution extern "C" DllExport void ufusr( char *parm, int *returnCode, int rlen ) { try { //代码在这里 UF_initialize(); uc1601(parm, 1); UF_terminate(); // Create NXOpen C++ class instance MyClass *theMyClass; theMyClass = new MyClass(); theMyClass->do_it(); delete theMyClass; } catch (const NXException& e1) { UI::GetUI()->NXMessageBox()->Show("NXException", NXOpen::NXMessageBox::DialogTypeError, e1.Message()); } catch (const exception& e2) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, e2.what()); } catch (...) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, "Unknown Exception."); } } //------------------------------------------------------------------------------ // Unload Handler //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { return (int)NXOpen::Session::LibraryUnloadOptionImmediately; }
演示
打断点调试,查看传入的参数
通过这个就可以做点击不同的Button按钮传入不同的ID来判断字符串参数调用执行不同的函数功能。
来实现一个dll,点击不同button按钮执行不同功能。
- ufsta()
这个也是我们做二次开发经常用到的入口函数,主要是用UDO的时候要用到这个入口,当然还有一些其他需求也会用到。
比如这个例子NX二次开发-自动将NX标题设置为prt路径
与ufusr()需要点击菜单按钮或者ctrl+u调用才会被执行加载有所不同,ufusr()当NX启动时就被激活执行函数中的内容了。
在用向导创建NX项目的时候,选择ufsta()
编译出来的dll,直接放到二次开发文件夹startup里,都不需要挂菜单,启动ug就会自动加载了。
源代码
//NX9_NXOpenCPP_Wizard9 // Mandatory UF Includes #include <uf.h> #include <uf_object_types.h> // Internal Includes #include <NXOpen/ListingWindow.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/UI.hxx> // Internal+External Includes #include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include <NXOpen/Assemblies_ComponentAssembly.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/BodyCollection.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Line.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/NXObject.hxx> #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include <NXOpen/Session.hxx> //头文件 #include <uf.h> #include <uf_ui.h> #include <uf_mb.h> // Std C++ Includes #include <iostream> #include <sstream> using namespace NXOpen; using std::string; using std::exception; using std::stringstream; using std::endl; using std::cout; using std::cerr; //------------------------------------------------------------------------------ // NXOpen c++ test class //------------------------------------------------------------------------------ class MyClass { // class members public: static Session *theSession; static UI *theUI; MyClass(); ~MyClass(); void do_it(); void print(const NXString &); void print(const string &); void print(const char*); private: Part *workPart, *displayPart; NXMessageBox *mb; ListingWindow *lw; LogFile *lf; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(MyClass::theSession) = NULL; UI *(MyClass::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ MyClass::MyClass() { // Initialize the NX Open C++ API environment MyClass::theSession = NXOpen::Session::GetSession(); MyClass::theUI = UI::GetUI(); mb = theUI->NXMessageBox(); lw = theSession->ListingWindow(); lf = theSession->LogFile(); workPart = theSession->Parts()->Work(); displayPart = theSession->Parts()->Display(); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ MyClass::~MyClass() { } //------------------------------------------------------------------------------ // Print string to listing window or stdout //------------------------------------------------------------------------------ void MyClass::print(const NXString &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const string &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const char * msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } //------------------------------------------------------------------------------ // Do something //------------------------------------------------------------------------------ void MyClass::do_it() { // TODO: add your code here } //------------------------------------------------------------------------------ // Entry point(s) for unmanaged internal NXOpen C/C++ programs //------------------------------------------------------------------------------ // NX Startup extern "C" DllExport void ufsta( char *param, int *returnCode, int rlen ) { try { UF_initialize(); UF_UI_open_listing_window(); UF_UI_write_listing_window("sb"); UF_terminate(); // Create NXOpen C++ class instance MyClass *theMyClass; theMyClass = new MyClass(); theMyClass->do_it(); delete theMyClass; } catch (const NXException& e1) { UI::GetUI()->NXMessageBox()->Show("NXException", NXOpen::NXMessageBox::DialogTypeError, e1.Message()); } catch (const exception& e2) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, e2.what()); } catch (...) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, "Unknown Exception."); } } //------------------------------------------------------------------------------ // Unload Handler //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { return (int)NXOpen::Session::LibraryUnloadOptionImmediately; }
演示
- 其他的入口函数例子
先贴一个书上的截图
这些User Exit的实现方式如下:在配置文件D:\Program Files\Siemens\NX 9.0\UGII\ugii_env_ug.dat中找到User Exit环境变量,
去掉环境变量左边的注释符"#",然后按照"环境变量=DLL全路径"格式进行修改,最后在应用开发程序中添加该User Exit出口函数
并编写代码。编译通过后触发User Exit即可执行用户应用程序。
ufget()
新建个项目
源代码
//NX9_NXOpenCPP_Wizard10 // Mandatory UF Includes #include <uf.h> #include <uf_object_types.h> // Internal Includes #include <NXOpen/ListingWindow.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/UI.hxx> // Internal+External Includes #include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include <NXOpen/Assemblies_ComponentAssembly.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/BodyCollection.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Line.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/NXObject.hxx> #include <NXOpen/Part.hxx> #include <NXOpen/PartCollection.hxx> #include <NXOpen/Session.hxx> //头文件 #include <uf.h> #include <uf_ui.h> // Std C++ Includes #include <iostream> #include <sstream> using namespace NXOpen; using std::string; using std::exception; using std::stringstream; using std::endl; using std::cout; using std::cerr; //------------------------------------------------------------------------------ // NXOpen c++ test class //------------------------------------------------------------------------------ class MyClass { // class members public: static Session *theSession; static UI *theUI; MyClass(); ~MyClass(); void do_it(); void print(const NXString &); void print(const string &); void print(const char*); private: Part *workPart, *displayPart; NXMessageBox *mb; ListingWindow *lw; LogFile *lf; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(MyClass::theSession) = NULL; UI *(MyClass::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ MyClass::MyClass() { // Initialize the NX Open C++ API environment MyClass::theSession = NXOpen::Session::GetSession(); MyClass::theUI = UI::GetUI(); mb = theUI->NXMessageBox(); lw = theSession->ListingWindow(); lf = theSession->LogFile(); workPart = theSession->Parts()->Work(); displayPart = theSession->Parts()->Display(); } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ MyClass::~MyClass() { } //------------------------------------------------------------------------------ // Print string to listing window or stdout //------------------------------------------------------------------------------ void MyClass::print(const NXString &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const string &msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } void MyClass::print(const char * msg) { if(! lw->IsOpen() ) lw->Open(); lw->WriteLine(msg); } //------------------------------------------------------------------------------ // Do something //------------------------------------------------------------------------------ void MyClass::do_it() { // TODO: add your code here } //------------------------------------------------------------------------------ // Entry point(s) for unmanaged internal NXOpen C/C++ programs //------------------------------------------------------------------------------ // Open Part User Exit extern "C" DllExport void ufget( char *param, int *returnCode, int rlen ) { try { UF_initialize(); uc1601("SB", 1); UF_terminate(); // Create NXOpen C++ class instance MyClass *theMyClass; theMyClass = new MyClass(); theMyClass->do_it(); delete theMyClass; } catch (const NXException& e1) { UI::GetUI()->NXMessageBox()->Show("NXException", NXOpen::NXMessageBox::DialogTypeError, e1.Message()); } catch (const exception& e2) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, e2.what()); } catch (...) { UI::GetUI()->NXMessageBox()->Show("Exception", NXOpen::NXMessageBox::DialogTypeError, "Unknown Exception."); } } //------------------------------------------------------------------------------ // Unload Handler //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { return (int)NXOpen::Session::LibraryUnloadOptionImmediately; }
打开配置文件,设置环境变量
USER_RETRIEVE=D:\1\NX9_NXOpenCPP_Wizard10\x64\Debug\NX9_NXOpenCPP_Wizard10.dll
演示
*注意事项
如果"*returnCode = 1",系统只执行NX用户在入口函数中定义的功能。
如果"*returnCode = 2",系统在执行完用户功能后还要执行NX原打开文件的功能。
这些API帮助上面都有说明。
今天就先更新到这里,内容太多,下次再更新。
阿飞
2021年9月4日