Advertisement
Guest User

my_dll.cpp

a guest
Oct 16th, 2013
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.92 KB | None | 0 0
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        my_dll.cpp
  3. // Purpose:     Sample showing how to use wx from a DLL
  4. // Author:      Vaclav Slavik
  5. // Created:     2009-12-03
  6. // Copyright:   (c) 2009 Vaclav Slavik
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. // ============================================================================
  11. // declarations
  12. // ============================================================================
  13.  
  14. // ----------------------------------------------------------------------------
  15. // headers
  16. // ----------------------------------------------------------------------------
  17.  
  18. #include "wx/wxprec.h"
  19.  
  20. #include "wx/app.h"
  21. #include "wx/dynlib.h"
  22. #include "wx/frame.h"
  23. #include "wx/panel.h"
  24. #include "wx/sizer.h"
  25. #include "wx/stattext.h"
  26. #include "wx/button.h"
  27. #include "wx/thread.h"
  28. #include "wx/msgdlg.h"
  29.  
  30. #include <pthread.h>
  31.  
  32. #include "my_dll.h"
  33.  
  34. // ----------------------------------------------------------------------------
  35. // GUI classes
  36. // ----------------------------------------------------------------------------
  37.  
  38. class MyDllFrame : public wxFrame
  39. {
  40. public:
  41.   MyDllFrame(wxWindow *parent, const wxString& label);
  42.  
  43.   void OnAbout(wxCommandEvent& event);
  44.  
  45.   DECLARE_EVENT_TABLE()
  46. };
  47.  
  48.  
  49. static const int CMD_SHOW_WINDOW = wxNewId();
  50. static const int CMD_TERMINATE = wxNewId();
  51.  
  52. class MyDllApp : public wxApp
  53. {
  54. public:
  55.   MyDllApp();
  56.  
  57. private:
  58.   void OnShowWindow(wxThreadEvent& event);
  59.   void OnTerminate(wxThreadEvent& event);
  60. };
  61.  
  62.  
  63. // ============================================================================
  64. // implementation
  65. // ============================================================================
  66.  
  67. // ----------------------------------------------------------------------------
  68. // MyDllFrame
  69. // ----------------------------------------------------------------------------
  70.  
  71. BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
  72. EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
  73. END_EVENT_TABLE()
  74.  
  75. MyDllFrame::MyDllFrame(wxWindow *parent, const wxString& label)
  76. : wxFrame(parent, wxID_ANY, label)
  77. {
  78.   wxPanel *p = new wxPanel(this, wxID_ANY);
  79.   wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
  80.  
  81.   sizer->Add
  82.     (
  83.      new wxStaticText
  84.      (
  85.       p, wxID_ANY,
  86.       wxString::Format
  87.       (
  88.        "Running using %s\n"
  89.        "wxApp instance is %p, thread ID %ld",
  90.        wxVERSION_STRING,
  91.        wxApp::GetInstance(),
  92.        wxThread::GetCurrentId()
  93.        )
  94.       ),
  95.      wxSizerFlags(1).Expand().Border(wxALL, 10)
  96.      );
  97.  
  98.   sizer->Add
  99.     (
  100.      new wxButton(p, wxID_ABOUT, "Show info"),
  101.      wxSizerFlags(0).Right().Border(wxALL, 10)
  102.      );
  103.  
  104.   p->SetSizerAndFit(sizer);
  105.  
  106.   wxSizer *fsizer = new wxBoxSizer(wxVERTICAL);
  107.   fsizer->Add(p, wxSizerFlags(1).Expand());
  108.   SetSizerAndFit(fsizer);
  109. }
  110.  
  111. void MyDllFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  112. {
  113.   wxMessageBox("This window is running in its own thread,\n"
  114.            "using private wxWidgets instance compiled into the DLL.",
  115.            "About",
  116.            wxOK | wxICON_INFORMATION);
  117. }
  118.  
  119.  
  120. // ----------------------------------------------------------------------------
  121. // MyDllApp
  122. // ----------------------------------------------------------------------------
  123.  
  124. MyDllApp::MyDllApp()
  125. {
  126.   // Keep the wx "main" thread running even without windows. This greatly
  127.   // simplifies threads handling, because we don't have to correctly
  128.   // implement wx-thread restarting.
  129.   //
  130.   // Note that this only works if you don't explicitly call ExitMainLoop(),
  131.   // except in reaction to wx_dll_cleanup()'s message. wx_dll_cleanup()
  132.   // relies on the availability of wxApp instance and if the event loop
  133.   // terminated, wxEntry() would return and wxApp instance would be
  134.   // destroyed.
  135.   //
  136.   // Also note that this is efficient, because if there are no windows, the
  137.   // thread will sleep waiting for a new event. We could safe some memory
  138.   // by shutting the thread down when it's no longer needed, though.
  139.   SetExitOnFrameDelete(false);
  140.  
  141.   Connect(CMD_SHOW_WINDOW,
  142.       wxEVT_THREAD,
  143.       wxThreadEventHandler(MyDllApp::OnShowWindow));
  144.   Connect(CMD_TERMINATE,
  145.       wxEVT_THREAD,
  146.       wxThreadEventHandler(MyDllApp::OnTerminate));
  147. }
  148.  
  149. void MyDllApp::OnShowWindow(wxThreadEvent& event)
  150. {
  151.   puts("received show window command");
  152.   wxFrame *f = new MyDllFrame(NULL, event.GetString());
  153.   f->Show(true);
  154. }
  155.  
  156. void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
  157. {
  158.   puts("received terminate command");
  159.   ExitMainLoop();
  160. }
  161.  
  162.  
  163. // ----------------------------------------------------------------------------
  164. // application startup
  165. // ----------------------------------------------------------------------------
  166.  
  167. // we can't have WinMain() in a DLL and want to start the app ourselves
  168. IMPLEMENT_APP_NO_MAIN(MyDllApp)
  169.  
  170. namespace
  171. {
  172.  
  173.   // Critical section that guards everything related to wxWidgets "main" thread
  174.   // startup or shutdown.
  175.   wxCriticalSection gs_wxStartupCS;
  176.   // Handle of wx "main" thread if running, NULL otherwise
  177.   bool mainThreadStarted = false;
  178.   bool wxInitialized = false;
  179.   pthread_t gs_wxMainThread;
  180.   pthread_mutex_t hMutex;
  181.   pthread_cond_t hEvent;
  182.  
  183.  
  184.   //  wx application startup code -- runs from its own thread
  185.   void* MyAppLauncher(void* event)
  186.   {
  187.     // Note: The thread that called run_wx_gui_from_dll() holds gs_wxStartupCS
  188.     //       at this point and won't release it until we signal it.
  189.  
  190.     // IMPLEMENT_WXWIN_MAIN does this as the first thing
  191.     wxDISABLE_DEBUG_SUPPORT();
  192.  
  193.     // We do this before wxEntry() explicitly, even though wxEntry() would
  194.     // do it too, so that we know when wx is initialized and can signal
  195.     // run_wx_gui_from_dll() about it *before* starting the event loop.
  196.     wxInitializer wxinit;
  197.     if ( !wxinit.IsOk() )
  198.       return 0; // failed to init wx
  199.  
  200.     // Signal run_wx_gui_from_dll() that it can continue
  201.    
  202.     pthread_mutex_lock(&hMutex);
  203.     wxInitialized = true;
  204.     pthread_cond_signal(&hEvent);
  205.     pthread_mutex_unlock(&hMutex);
  206.  
  207.     // Run the app:
  208.     puts("applauncher: calling wxEntry");
  209.     int argc = 0;
  210.     wxEntry(argc, (wxChar**)NULL);
  211.  
  212.     pthread_exit(NULL);
  213.   }
  214.  
  215. } // anonymous namespace
  216.  
  217. // ----------------------------------------------------------------------------
  218. // public DLL interface
  219. // ----------------------------------------------------------------------------
  220.  
  221. extern "C"
  222. {
  223.  
  224.   void run_wx_gui_from_dll(const char *title)
  225.   {
  226.     // In order to prevent conflicts with hosting app's event loop, we
  227.     // launch wx app from the DLL in its own thread.
  228.     //
  229.     // We can't even use wxInitializer: it initializes wxModules and one of
  230.     // the modules it handles is wxThread's private module that remembers
  231.     // ID of the main thread. But we need to fool wxWidgets into thinking that
  232.     // the thread we are about to create now is the main thread, not the one
  233.     // from which this function is called.
  234.     //
  235.     // Note that we cannot use wxThread here, because the wx library wasn't
  236.     // initialized yet. wxCriticalSection is safe to use, though.
  237.  
  238.     wxCriticalSectionLocker lock(gs_wxStartupCS);
  239.  
  240.     if ( !mainThreadStarted )
  241.       {
  242.         pthread_attr_t attr;
  243.  
  244.         pthread_mutex_init(&hMutex, NULL);
  245.         pthread_cond_init(&hEvent, NULL);
  246.  
  247.         pthread_attr_init(&attr);
  248.         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  249.  
  250.         int err = pthread_create(&gs_wxMainThread, &attr, &MyAppLauncher, NULL);
  251.  
  252.         pthread_attr_destroy(&attr);
  253.  
  254.         if ( err )
  255.       {
  256.             pthread_mutex_destroy(&hMutex);
  257.             pthread_cond_destroy(&hEvent);
  258.             puts("run: failed to create gs_wxMainThread");
  259.             return; //error
  260.       }
  261.  
  262.         mainThreadStarted = true;
  263.  
  264.         pthread_mutex_lock(&hMutex);
  265.         while (!wxInitialized) {
  266.       puts("run: wait for wx to init");
  267.       pthread_cond_wait(&hEvent, &hMutex);
  268.         }
  269.         pthread_mutex_unlock(&hMutex);
  270.  
  271.     pthread_cond_destroy(&hEvent);
  272.       }
  273.  
  274.     // Send a message to wx thread to show a new frame:
  275.     wxThreadEvent *event =
  276.       new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);
  277.     event->SetString(title);
  278.     wxQueueEvent(wxApp::GetInstance(), event);
  279.  
  280.     sleep(3);
  281.   }
  282.  
  283.   void wx_dll_cleanup()
  284.   {
  285.     wxCriticalSectionLocker lock(gs_wxStartupCS);
  286.  
  287.     if ( !mainThreadStarted ) {
  288.       puts("cleanup: main thread not started");
  289.       return;
  290.     }
  291.  
  292.     // If wx main thread is running, we need to stop it. To accomplish this,
  293.     // send a message telling it to terminate the app.
  294.     wxThreadEvent *event =
  295.       new wxThreadEvent(wxEVT_THREAD, CMD_TERMINATE);
  296.     wxQueueEvent(wxApp::GetInstance(), event);
  297.  
  298.     // We must then wait for the thread to actually terminate.
  299.     puts("cleanup: waiting for main thread to finish");
  300.     pthread_join(gs_wxMainThread, NULL);
  301.     pthread_mutex_destroy(&hMutex);
  302.   }
  303.  
  304. } // extern "C"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement