Juce源代码分析(九)应用程序基类ApplicationBase

此前文章分析Juce库Core模块内存部分,不受大众关注。此次分析Juce上层应用程序框架,给出Windows部分代码片段,介绍了WinMain函数执行内容、消息循环及善后处理,还分析了应用程序初始化,且指出其利用栈对象析构原理管理对象生命周期值得借鉴。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         在前面的几篇文章,分析的都是Juce库里面Core模块的内存部分,除了骨灰级C++爱好者之外,貌似大家对这些都不是非常感兴趣。相信大家更想知道Juce是怎么用于产品开发,而对于它的构成不是非常感兴趣。天天写一些内存、指针、线程之类的文章。Skilla也厌倦了。这次来分析一下Juce的上层应用程序框架。

         以下上一段Demo里的代码片段

  1. class JuceDemoApplication : public JUCEApplication
  2. {
  3. public:
  4. JuceDemoApplication() {}
  5. //==============================================================================
  6. void initialise (const String& commandLine) override
  7. {
  8. if (invokeChildProcessDemo (commandLine))
  9. return;
  10. Desktop::getInstance().setOrientationsEnabled (Desktop::allOrientations);
  11. // Do your application's initialisation code here..
  12. mainWindow = new MainAppWindow();
  13. }
  14. void shutdown() override
  15. {
  16. // Do your application's shutdown code here..
  17. mainWindow = nullptr;
  18. }
  19. //==============================================================================
  20. void systemRequestedQuit() override
  21. {
  22. // This gets called when the OS wants our app to quit. You may want to
  23. // ask the user to save documents, close windows, etc here, but in this
  24. // case we'll just call quit(), which tells the message loop to stop and
  25. // allows the app to (asynchronously) exit.
  26. quit();
  27. }
  28. //==============================================================================
  29. const String getApplicationName() override
  30. {
  31. return "JuceDemo";
  32. }
  33. const String getApplicationVersion() override
  34. {
  35. return ProjectInfo::versionString;
  36. }
  37. bool moreThanOneInstanceAllowed() override
  38. {
  39. return true;
  40. }
  41. void anotherInstanceStarted (const String& /*commandLine*/) override
  42. {
  43. }
  44. private:
  45. ScopedPointer<MainAppWindow> mainWindow;
  46. };
  47. //==============================================================================
  48. // This macro generates the main() routine that starts the app.
  49. START_JUCE_APPLICATION(JuceDemoApplication)

           假设你看过Juce里面的Demo的话,一定对这个类很熟悉了,没错。这个就是JuceDemo里的应用程序类。当你第一次见到它时,首先应该想到的是什么?这是我们应该能联想到,学完Win32时初学MFC时的场景,一个很蛋疼的问题是:这玩意怎么执行,它的WinMain函数在哪里?第一次找MFC的WinMain函数时的感觉。相信大家都体验过,不停的按F11,好像穿越了几个世纪一样,见到的都是一个一个的陌生”面孔“,上个厕所的功夫回来就能忘得一干二净,分析源代码的感觉让人感到彷徨,然而却很刺激。相比之下Juce的刺激性小多了,对着START_JUCE_APPLICATION按F11一次就看到了WinMain。

  1. #if JUCE_WINDOWS && ! defined (_CONSOLE)
  2. #define JUCE_MAIN_FUNCTION int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
  3. #define JUCE_MAIN_FUNCTION_ARGS
  4. #else
  5. #define JUCE_MAIN_FUNCTION int main (int argc, char* argv[])
  6. #define JUCE_MAIN_FUNCTION_ARGS argc, (const char**) argv
  7. #endif
  8. #define START_JUCE_APPLICATION(AppClass) \
  9. static juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } \
  10. extern "C" JUCE_MAIN_FUNCTION \
  11. { \
  12. juce::JUCEApplicationBase::createInstance = &juce_CreateApplication; \
  13. return juce::JUCEApplicationBase::main (JUCE_MAIN_FUNCTION_ARGS); \
  14. }
  15. #endif


忽略其它平台,单纯看Windows部分,START_JUCE_APPLICATION等价于以下的代码

  1. static juce::JUCEApplicationBase* juce_CreateApplication() { return new JuceDemoApplication(); }
  2. extern "C" int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
  3. {
  4. juce::JUCEApplicationBase::createInstance = &juce_CreateApplication;
  5. return juce::JUCEApplicationBase::main ();
  6. }

WinMain函数真正执行的是里面的静态成员函数main()

  1. int JUCEApplicationBase::main()
  2. {
  3. ScopedJuceInitialiser_GUI libraryInitialiser;
  4. jassert (createInstance != nullptr);
  5. const ScopedPointer<JUCEApplicationBase> app (createInstance());
  6. jassert (app != nullptr);
  7. if (! app->initialiseApp())
  8. return app->getApplicationReturnValue();
  9. JUCE_TRY
  10. {
  11. // loop until a quit message is received..
  12. MessageManager::getInstance()->runDispatchLoop();
  13. }
  14. JUCE_CATCH_EXCEPTION
  15. return app->shutdownApp();
  16. }
          ScopedJuceInitialiser_GUI用于创建MessageManager(消息管理器的)单例,但同一时候也肩负着将它析构的重任,在ScopedPointer的管理下。里面的局部对象app相同也是自生自灭。app->initialiseApp()用于应用程序的初始化,一般应用层的初始化和窗体的创建都在这里实现。

再以下一句代码是MessageManager::getInstance()->runDispatchLoop();。这句代码是写的最短的。然而却是执行时间最长的,它就是我们最为熟知的消息循环。最后的shutdownApp则是善后处理并调用子类的shutdown成员函数,作为应用程序结束的通知,ShutdownApp返回以后WinMain函数就结束了。继而MessageManage的单例和app对象被作用域析构掉。由此可见,这样设计是合情合理的。这一章我们主要分析initialiseApp()看一下应用程序是怎么初始化的。

  1. bool JUCEApplicationBase::initialiseApp()
  2. {
  3. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  4. if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance())
  5. {
  6. DBG ("Another instance is running - quitting...");
  7. return false;
  8. }
  9. #endif
  10. // let the app do its setting-up..
  11. initialise (getCommandLineParameters());
  12. stillInitialising = false;
  13. if (MessageManager::getInstance()->hasStopMessageBeenSent())
  14. return false;
  15. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  16. if (multipleInstanceHandler != nullptr)
  17. MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);
  18. #endif
  19. return true;
  20. }
         最開始的if推断语句的目的是,推断应用程序是否同意多个实例同一时候进行而且查看是否当前有实例正在执行,由于有的软件是不同意”双开“或”多开“,这里能够依据须要重载moreThanOneInstanceAllowed()方法。 initialise (getCommandLineParameters());的功能是获取命令行參数,传给子类并完毕子类的初始化操作。  if (MessageManager::getInstance()->hasStopMessageBeenSent())   return false;  这一句是推断消息管理器是否收到了退出消息。   if (multipleInstanceHandler != nullptr)
        MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);这一句是注冊进程通信的监听器。

这些操作完毕之后,就是消息循环了。


        在ApplicationBase的成员函数main()中我们看到,作者巧妙地利用了栈对象的自己主动析构原理来管理MessageManager和ApplicationBase两个对象的生命周期,使之初始化时机合理。析构时机亦合理,这点值得借鉴。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值