瞎鸡儿写写。有不对的地方欢迎指正。

最近做一点需求在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

版权声明:本文为haovcf原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/haovcf/p/14890381.html