filezilla 3.7.2 Client 入口分析
瞎鸡儿写写。有不对的地方欢迎指正。
最近做一点需求在filezilla上。需要编译filezilla。了解filezilla的工作机制。下载好filezilla源码(3.7.2)。
vs2019打开(需要将filezilla源码\src\Dependencies.props.example 重命名Dependencies.props。并设置好所需的依赖项)。
熟悉的搜索main(),结果没有搜到。怎么办呢。运行filezilla程序。windbg 附加到filezilla进程。打印栈。可以获知入口点 IMPLEMENT_APP(CFileZillaApp)
后来知道这个入口是wxWidgets库的。整个逻辑还是比较复杂。因此有了这篇随笔。 我 用的 wxWidgets 是3.1.5的。
好了,进入正文
filezilla.cpp 入口定义 定义在 filezilla工程中 interface\FileZilla.cpp
1 #if !defined(__WXGTK__) && !defined(__MINGW32__) 2 IMPLEMENT_APP(CFileZillaApp) 3 #else 4 IMPLEMENT_APP_NO_MAIN(CFileZillaApp) 5 #endif //__WXGTK__
查看IMPLEMENT_APP 的实现 在wxWidgets 工程中 wx\app.h
以下部分,绝大多数都是在wxWidgets 中。
1 #define IMPLEMENT_APP(app) wxIMPLEMENT_APP(app); 2 #define wxIMPLEMENT_APP(appname) \ 3 wxIMPLEMENT_WX_THEME_SUPPORT \ 4 wxIMPLEMENT_APP_NO_THEMES(appname)
wxIMPLEMENT_WX_THEME_SUPPORT 用来支持主题的。只有在 __WXUNIVERSAL__定义的时候才有效。vs编译下没有定义。wxWidgets可以支持两种theme(win32和gtk).其他情况使用原生主题。
#ifdef __WXUNIVERSAL__ 2 #include "wx/univ/theme.h" 3 4 #ifdef wxUNIV_DEFAULT_THEME 5 #define wxIMPLEMENT_WX_THEME_SUPPORT \ 6 WX_USE_THEME(wxUNIV_DEFAULT_THEME); 7 #else 8 #define wxIMPLEMENT_WX_THEME_SUPPORT 9 #endif 10 #else 11 #define wxIMPLEMENT_WX_THEME_SUPPORT 12 #endif
wxIMPLEMENT_APP_NO_THEMES 的实现如下
1 #define wxIMPLEMENT_APP_NO_THEMES(appname) \ 2 wxIMPLEMENT_WXWIN_MAIN \ 3 wxIMPLEMENT_APP_NO_MAIN(appname)
wxIMPLEMENT_WXWIN_MAIN 的定义 如下
1 #ifndef wxIMPLEMENT_WXWIN_MAIN 2 #define wxIMPLEMENT_WXWIN_MAIN wxIMPLEMENT_WXWIN_MAIN_CONSOLE 3 #endif // defined(wxIMPLEMENT_WXWIN_MAIN)
但实际上 wxIMPLEMENT_WXWIN_MAIN 已被定义。
首先在 wx\app.h 中包含头文件
1 #include "wx/init.h" // we must declare wxEntry()
在 wx/init.h定义中有预编译宏如下:
1 // Under Windows we define additional wxEntry() overloads with signature 2 // compatible with WinMain() and not the traditional main(). 3 #ifdef __WINDOWS__ 4 #include "wx/msw/init.h" 5 #endif
在 wx\msw\init.h中,定义了预编译宏wxIMPLEMENT_WXWIN_MAIN
1 #define wxIMPLEMENT_WXWIN_MAIN \ 2 extern "C" int WINAPI WinMain(HINSTANCE hInstance, \ 3 HINSTANCE hPrevInstance, \ 4 wxCmdLineArgType lpCmdLine, \ 5 int nCmdShow) \ 6 { \ 7 wxDISABLE_DEBUG_SUPPORT(); \ 8 \ 9 return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow); \ 10 }
wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow) 的实现在 msw\main.cpp
定义如下
1 WXDLLEXPORT int wxEntry(HINSTANCE hInstance, 2 HINSTANCE WXUNUSED(hPrevInstance), 3 wxCmdLineArgType WXUNUSED(pCmdLine), 4 int nCmdShow) 5 { 6 if ( !wxMSWEntryCommon(hInstance, nCmdShow) ) 7 return -1; 8 9 return wxEntry(wxArgs.argc, wxArgs.argv); 10 }
wxMSWEntryCommon 同在msw\main.cpp 实现如下
1 static wxMSWCommandLineArguments wxArgs;
2 static boolwxMSWEntryCommon(HINSTANCE hInstance, int nCmdShow) 3 { 4 // remember the parameters Windows gave us 5 wxSetInstance(hInstance); 6 #ifdef __WXMSW__ 7 wxApp::m_nCmdShow = nCmdShow; 8 #endif 9 10 wxArgs.Init(); 11 12 return true; 13 }
wxMSWCommandLineArguments 是个全局类,用来解析命令行参数。
wxEntry 调用的 wxEntry 实现还是在main.cpp,代码如下。
1 int wxEntry(int& argc, wxChar **argv) 2 { 3 DisableAutomaticSETranslator(); 4 5 wxSEH_TRY 6 { 7 return wxEntryReal(argc, argv); 8 } 9 wxSEH_HANDLE(-1) 10 }
在看wxEntryReal 前需要先看看另一个宏定义。 还记得 wxIMPLEMENT_APP_NO_THEMES 宏定义包含两个宏定义。如下。
1 #define wxIMPLEMENT_APP_NO_THEMES(appname) \
2 wxIMPLEMENT_WXWIN_MAIN \
3 wxIMPLEMENT_APP_NO_MAIN(appname)
上面说的都是 wxIMPLEMENT_WXWIN_MAIN 宏定义的实现。
现在看看 wxIMPLEMENT_APP_NO_MAIN(appname)的实现。
定义如下:
1 #define wxIMPLEMENT_APP_NO_MAIN(appname) \ 2 appname& wxGetApp() { return *static_cast<appname*>(wxApp::GetInstance()); } \ 3 wxAppConsole *wxCreateApp() \ 4 { \ 5 wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, \ 6 "your program"); \ 7 return new appname; \ 8 } \ 9 wxAppInitializer \ 10 wxTheAppInitializer((wxAppInitializerFunction) wxCreateApp) 11 12 extern wxAppInitializer wxTheAppInitializer;
上面的宏定义不包含 extern. 重要的是后面9到10行。 wxAppInitializer 是一个类。定义wx\app.h 实现如下
1 class WXDLLIMPEXP_BASE wxAppInitializer 2 { 3 public: 4 wxAppInitializer(wxAppInitializerFunction fn) 5 { wxApp::SetInitializerFunction(fn); } 6 };
因为平台是 windows平台。所以包含的头文件是wx/msw/app.h
wxApp 类中没有定义SetInitializerFunction 函数。查看wxApp类继承关系。如下
1 class WXDLLIMPEXP_CORE wxApp : public wxAppBase 2 { 3 }; 4 5 class WXDLLIMPEXP_CORE wxAppBase : public wxAppConsole 6 { 7 }
wxAppConsole 通过预编译指定。此处继承 wxAppConsoleBase。代码如下
1 #if defined(__UNIX__) && !defined(__WINDOWS__) 2 #include "wx/unix/app.h" 3 #else 4 // this has to be a class and not a typedef as we forward declare it 5 class wxAppConsole : public wxAppConsoleBase { }; 6 #endif
wxAppConsoleBase 这个类中定义了SetInitializerFunction 函数定义。代码如下
1 static void SetInitializerFunction(wxAppInitializerFunction fn) 2 { ms_appInitFn = fn; } 3 static wxAppInitializerFunction GetInitializerFunction() 4 { return ms_appInitFn; }
ms_appInitFn 是 wxAppConsoleBase 静态成员变量。定义在 common\appbase.cpp
1 static wxAppInitializerFunction ms_appInitFn;
总之 wxIMPLEMENT_APP_NO_MAIN 宏定义就是 在全局变量中保存一个函数指针。这个函数是用来创建一个 CFileZillaApp的实例对象。
有了这些基础再来看 wxEntryReal 函数。这个函数定义在common\init.cpp中。
1 int wxEntryReal(int& argc, wxChar **argv) 2 { 3 // library initialization 4 wxInitializer initializer(argc, argv); 5 6 if ( !initializer.IsOk() ) 7 { 8 #if wxUSE_LOG 9 // flush any log messages explaining why we failed 10 delete wxLog::SetActiveTarget(NULL); 11 #endif 12 return -1; 13 } 14 15 wxTRY 16 { 17 // app initialization 18 if ( !wxTheApp->CallOnInit() ) 19 { 20 // don\'t call OnExit() if OnInit() failed 21 return -1; 22 } 23 24 // ensure that OnExit() is called if OnInit() had succeeded 25 class CallOnExit 26 { 27 public: 28 ~CallOnExit() { wxTheApp->OnExit(); } 29 } callOnExit; 30 31 WX_SUPPRESS_UNUSED_WARN(callOnExit); 32 33 // app execution 34 return wxTheApp->OnRun(); 35 } 36 wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) 37 }
先看第一行 wxInitializer initializer(argc, argv); 省去了一些不重要的代码如下:
1 class WXDLLIMPEXP_BASE wxInitializer 2 { 3 public: 4 wxInitializer(int& argc, wxChar **argv) 5 { 6 m_ok = wxInitialize(argc, argv); 7 } 8 };
使用带参构造,内部调用 wxInitialize(argc, argv);
1 bool wxInitialize(int& argc, wxChar **argv) 2 { 3 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); 4 5 if ( gs_initData.nInitCount++ ) 6 { 7 // already initialized 8 return true; 9 } 10 11 return wxEntryStart(argc, argv); 12 }
可以看到wxInitialize内容使用了引用机制。避免多次初始化。
没初始化的话,调用 wxEntryStart。以下是wxEntryStart的实现。省去了部分代码。
1 bool wxEntryStart(int& argc, wxChar **argv) 2 { 3 // do minimal, always necessary, initialization 4 // -------------------------------------------- 5 6 // initialize wxRTTI 7 if ( !DoCommonPreInit() ) 8 return false; 9 10 11 // first of all, we need an application object 12 // ------------------------------------------- 13 14 // the user might have already created it himself somehow 15 wxAppPtr app(wxTheApp); 16 if ( !app.get() ) 17 { 18 // if not, he might have used wxIMPLEMENT_APP() to give us a 19 // function to create it 20 wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); 21 22 if ( fnCreate ) 23 { 24 // he did, try to create the custom wxApp object 25 app.Set((*fnCreate)()); 26 } 27 } 28 29 if ( !app.get() ) 30 { 31 // either wxIMPLEMENT_APP() was not used at all or it failed -- in 32 // any case we still need something 33 app.Set(new wxDummyConsoleApp); 34 } 35 36 37 // wxApp initialization: this can be customized 38 // -------------------------------------------- 39 40 if ( !app->Initialize(argc, argv) ) 41 return false; 42 43 }
wxEntryStart 先做了一些通用初始化。 然后构造了一个wxAppPtr。wxAppPtr 是个啥东东。代码如下
1 class wxAppPtr : public wxAppPtrBase 2 { 3 public: 4 explicit wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } 5 ~wxAppPtr() 6 { 7 if ( get() ) 8 { 9 // the pointer is going to be deleted in the base class dtor, don\'t 10 // leave the dangling pointer! 11 wxApp::SetInstance(NULL); 12 } 13 } 14 15 void Set(wxAppConsole *ptr) 16 { 17 reset(ptr); 18 19 wxApp::SetInstance(ptr); 20 } 21 22 wxDECLARE_NO_COPY_CLASS(wxAppPtr); 23 };
wxAppPtr 没有实现 get函数。看看父类 wxAppPtrBase 实现。
父类是 通过如下宏定义定义的。
1 // we need a special kind of auto pointer to wxApp which not only deletes the 2 // pointer it holds in its dtor but also resets the global application pointer 3 wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) 4 wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
查看宏定义。wxDEFINE_SCOPED_PTR 的实现。代码如下。
1 #define wxDECLARE_SCOPED_PTR(T, name) \ 2 class name \ 3 { \ 4 private: \ 5 T * m_ptr; \ 6 \ 7 name(name const &); \ 8 name & operator=(name const &); \ 9 \ 10 public: \ 11 explicit name(T * ptr = NULL) \ 12 : m_ptr(ptr) { } \ 13 \ 14 ~name(); \ 15 \ 16 void reset(T * ptr = NULL); \ 17 \ 18 T *release() \ 19 { \ 20 T *ptr = m_ptr; \ 21 m_ptr = NULL; \ 22 return ptr; \ 23 } \ 24 \ 25 T & operator*() const \ 26 { \ 27 wxASSERT(m_ptr != NULL); \ 28 return *m_ptr; \ 29 } \ 30 \ 31 T * operator->() const \ 32 { \ 33 wxASSERT(m_ptr != NULL); \ 34 return m_ptr; \ 35 } \ 36 \ 37 T * get() const \ 38 { \ 39 return m_ptr; \ 40 } \ 41 \ 42 void swap(name & ot) \ 43 { \ 44 T * tmp = ot.m_ptr; \ 45 ot.m_ptr = m_ptr; \ 46 m_ptr = tmp; \ 47 } \ 48 }; 49 50 #define wxDEFINE_SCOPED_PTR(T, name)\ 51 void name::reset(T * ptr) \ 52 { \ 53 if (m_ptr != ptr) \ 54 { \ 55 wxCHECKED_DELETE(m_ptr); \ 56 m_ptr = ptr; \ 57 } \ 58 } \ 59 name::~name() \ 60 { \ 61 wxCHECKED_DELETE(m_ptr); \ 62 } 63 64 // this macro can be used for the most common case when you want to declare and 65 // define the scoped pointer at the same time and want to use the standard 66 // naming convention: auto pointer to Foo is called FooPtr 67 #define wxDEFINE_SCOPED_PTR_TYPE(T) \ 68 wxDECLARE_SCOPED_PTR(T, T ## Ptr) \ 69 wxDEFINE_SCOPED_PTR(T, T ## Ptr) 70 71 // ---------------------------------------------------------------------------- 72 // "Tied" scoped pointer: same as normal one but also sets the value of 73 // some other variable to the pointer value 74 // ---------------------------------------------------------------------------- 75 76 #define wxDEFINE_TIED_SCOPED_PTR_TYPE(T) \ 77 wxDEFINE_SCOPED_PTR_TYPE(T) \ 78 class T ## TiedPtr : public T ## Ptr \ 79 { \ 80 public: \ 81 T ## TiedPtr(T **pp, T *p) \ 82 : T ## Ptr(p), m_pp(pp) \ 83 { \ 84 m_pOld = *pp; \ 85 *pp = p; \ 86 } \ 87 \ 88 ~ T ## TiedPtr() \ 89 { \ 90 *m_pp = m_pOld; \ 91 } \ 92 \ 93 private: \ 94 T **m_pp; \ 95 T *m_pOld; \ 96 }
使用模板技术,加宏定义实现。
wxAppPtr app(wxTheApp); 构造使用wxTheApp 作为参数。
wxTheApp 又是怎么定义的。
1 #define wxTheApp static_cast<wxApp*>(wxApp::GetInstance())
先分析宏定义。 wxTheApp 代表 wxApp::GetInstance()的实例。返回值转换成wxApp类型的指针。
因为还没有地方调用wxApp::GetInstance() 所以。app 构造时候传入参数为空。至少我调试的时候是空。
app.get() 为空,进入if 语句。执行语句。
1 wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); 2 3 if ( fnCreate ) 4 { 5 // he did, try to create the custom wxApp object 6 app.Set((*fnCreate)()); 7 }
wxApp::GetInitializerFunction() 获得了之前保存的函数指针。然后调用这个函数。就是创建CFileZillaApp 实例对象。将这个实例地址保存。
后续使用app 就可以 CFileZillaApp 实例对象划等号了。 然后执行了app.Initialize()函数。CFileZillaApp类没有实现 Initialize.
实现在CFileZillaApp的父类中 wxApp中。源码在msw/app.cpp.
1 bool wxApp::Initialize(int& argc_, wxChar **argv_) 2 { 3 if ( !wxAppBase::Initialize(argc_, argv_) ) 4 return false; 5 6 // ensure that base cleanup is done if we return too early 7 wxCallBaseCleanup callBaseCleanup(this); 8 9 InitCommonControls(); 10 11 wxSetKeyboardHook(true); 12 13 callBaseCleanup.Dismiss(); 14 15 return true; 16 }
app.Initialize()执行完以后,执行了一些其他操作。随后依次返回到 函数 wxEntryReal 中。
在try 语句中执行了函数 wxTheApp->CallOnInit()。 这个函数实现如下 。定义在 wx\app.h中。
1 // This gives wxCocoa a chance to call OnInit() with a memory pool in place 2 virtual bool CallOnInit() { return OnInit(); } 3 4 // Called before OnRun(), this is a good place to do initialization -- if 5 // anything fails, return false from here to prevent the program from 6 // continuing. The command line is normally parsed here, call the base 7 // class OnInit() to do it. 8 virtual bool OnInit(); 9 10 // This is the replacement for the normal main(): all program work should 11 // be done here. When OnRun() returns, the programs starts shutting down. 12 virtual int OnRun();
13 virtual int OnExit();
CFileZillaApp 子类实现了自己的OnInit 函数 。所以调用是CFileZillaApp::OnInit()函数。
接下来定义了一个类。CallOnExit 类。类只实现了一个析构函数。定义在try 块中。 也就是离开try块前。就会调用CallOnExit的析构函数。
CallOnExit 析构函数 实际上是调用的CFileZillaApp::OnExit(). 给CFileZillaApp 一个处理机会。
最后执行 wxTheApp->OnRun();CFileZillaApp 没有实现OnRun()函数。所以要看父类的实现。
继承关系如下
1 class CFileZillaApp : public wxApp 2 { 3 } 4 5 class WXDLLIMPEXP_CORE wxApp : public wxAppBase 6 { 7 }; 8 9 class WXDLLIMPEXP_CORE wxAppBase : public wxAppConsole 10 { 11 } 12 13 #if defined(__UNIX__) && !defined(__WINDOWS__) 14 #include "wx/unix/app.h" 15 #else 16 // this has to be a class and not a typedef as we forward declare it 17 class wxAppConsole : public wxAppConsoleBase { }; 18 #endif
wxApp 也没找到实现。 在wxAppBase找到实现。代码如下
1 int wxAppBase::OnRun() 2 { 3 // see the comment in ctor: if the initial value hasn\'t been changed, use 4 // the default Yes from now on 5 if ( m_exitOnFrameDelete == Later ) 6 { 7 m_exitOnFrameDelete = Yes; 8 } 9 //else: it has been changed, assume the user knows what he is doing 10 11 return wxAppConsole::OnRun(); 12 }
wxAppConsole 中没有实现OnRun()函数。继续像上查找。
wxAppConsoleBase 中找到实现。代码如下:
int wxAppConsoleBase::OnRun() { return MainLoop(); }
1 int wxAppConsoleBase::MainLoop() 2 { 3 wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop()); 4 5 if (wxTheApp) 6 wxTheApp->OnLaunched(); 7 8 return m_mainLoop ? m_mainLoop->Run() : -1; 9 }
到这里就基本结束了。
想不到一个入门main 能写出来如此复杂的代码。感觉十分复杂。各种抽象继承。为了健康,远离C++。
先提交,有时间在优化优化。有什么留言。
参考 :https://www.cnblogs.com/hgwang/p/6171309.html
https://blog.csdn.net/shendu369/article/details/6988456