Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /////////////////////////////////////////////////////////////////////////////
- // Name: my_dll.cpp
- // Purpose: Sample showing how to use wx from a DLL
- // Author: Vaclav Slavik
- // Created: 2009-12-03
- // Copyright: (c) 2009 Vaclav Slavik
- // Licence: wxWindows licence
- /////////////////////////////////////////////////////////////////////////////
- // ============================================================================
- // declarations
- // ============================================================================
- // ----------------------------------------------------------------------------
- // headers
- // ----------------------------------------------------------------------------
- #include "wx/wxprec.h"
- #include "wx/app.h"
- #include "wx/dynlib.h"
- #include "wx/frame.h"
- #include "wx/panel.h"
- #include "wx/sizer.h"
- #include "wx/stattext.h"
- #include "wx/button.h"
- #include "wx/thread.h"
- #include "wx/msgdlg.h"
- #include <pthread.h>
- #include "my_dll.h"
- // ----------------------------------------------------------------------------
- // GUI classes
- // ----------------------------------------------------------------------------
- class MyDllFrame : public wxFrame
- {
- public:
- MyDllFrame(wxWindow *parent, const wxString& label);
- void OnAbout(wxCommandEvent& event);
- DECLARE_EVENT_TABLE()
- };
- static const int CMD_SHOW_WINDOW = wxNewId();
- static const int CMD_TERMINATE = wxNewId();
- class MyDllApp : public wxApp
- {
- public:
- MyDllApp();
- private:
- void OnShowWindow(wxThreadEvent& event);
- void OnTerminate(wxThreadEvent& event);
- };
- // ============================================================================
- // implementation
- // ============================================================================
- // ----------------------------------------------------------------------------
- // MyDllFrame
- // ----------------------------------------------------------------------------
- BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
- EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
- END_EVENT_TABLE()
- MyDllFrame::MyDllFrame(wxWindow *parent, const wxString& label)
- : wxFrame(parent, wxID_ANY, label)
- {
- wxPanel *p = new wxPanel(this, wxID_ANY);
- wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
- sizer->Add
- (
- new wxStaticText
- (
- p, wxID_ANY,
- wxString::Format
- (
- "Running using %s\n"
- "wxApp instance is %p, thread ID %ld",
- wxVERSION_STRING,
- wxApp::GetInstance(),
- wxThread::GetCurrentId()
- )
- ),
- wxSizerFlags(1).Expand().Border(wxALL, 10)
- );
- sizer->Add
- (
- new wxButton(p, wxID_ABOUT, "Show info"),
- wxSizerFlags(0).Right().Border(wxALL, 10)
- );
- p->SetSizerAndFit(sizer);
- wxSizer *fsizer = new wxBoxSizer(wxVERTICAL);
- fsizer->Add(p, wxSizerFlags(1).Expand());
- SetSizerAndFit(fsizer);
- }
- void MyDllFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
- {
- wxMessageBox("This window is running in its own thread,\n"
- "using private wxWidgets instance compiled into the DLL.",
- "About",
- wxOK | wxICON_INFORMATION);
- }
- // ----------------------------------------------------------------------------
- // MyDllApp
- // ----------------------------------------------------------------------------
- MyDllApp::MyDllApp()
- {
- // Keep the wx "main" thread running even without windows. This greatly
- // simplifies threads handling, because we don't have to correctly
- // implement wx-thread restarting.
- //
- // Note that this only works if you don't explicitly call ExitMainLoop(),
- // except in reaction to wx_dll_cleanup()'s message. wx_dll_cleanup()
- // relies on the availability of wxApp instance and if the event loop
- // terminated, wxEntry() would return and wxApp instance would be
- // destroyed.
- //
- // Also note that this is efficient, because if there are no windows, the
- // thread will sleep waiting for a new event. We could safe some memory
- // by shutting the thread down when it's no longer needed, though.
- SetExitOnFrameDelete(false);
- Connect(CMD_SHOW_WINDOW,
- wxEVT_THREAD,
- wxThreadEventHandler(MyDllApp::OnShowWindow));
- Connect(CMD_TERMINATE,
- wxEVT_THREAD,
- wxThreadEventHandler(MyDllApp::OnTerminate));
- }
- void MyDllApp::OnShowWindow(wxThreadEvent& event)
- {
- puts("received show window command");
- wxFrame *f = new MyDllFrame(NULL, event.GetString());
- f->Show(true);
- }
- void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
- {
- puts("received terminate command");
- ExitMainLoop();
- }
- // ----------------------------------------------------------------------------
- // application startup
- // ----------------------------------------------------------------------------
- // we can't have WinMain() in a DLL and want to start the app ourselves
- IMPLEMENT_APP_NO_MAIN(MyDllApp)
- namespace
- {
- // Critical section that guards everything related to wxWidgets "main" thread
- // startup or shutdown.
- wxCriticalSection gs_wxStartupCS;
- // Handle of wx "main" thread if running, NULL otherwise
- bool mainThreadStarted = false;
- bool wxInitialized = false;
- pthread_t gs_wxMainThread;
- pthread_mutex_t hMutex;
- pthread_cond_t hEvent;
- // wx application startup code -- runs from its own thread
- void* MyAppLauncher(void* event)
- {
- // Note: The thread that called run_wx_gui_from_dll() holds gs_wxStartupCS
- // at this point and won't release it until we signal it.
- // IMPLEMENT_WXWIN_MAIN does this as the first thing
- wxDISABLE_DEBUG_SUPPORT();
- // We do this before wxEntry() explicitly, even though wxEntry() would
- // do it too, so that we know when wx is initialized and can signal
- // run_wx_gui_from_dll() about it *before* starting the event loop.
- wxInitializer wxinit;
- if ( !wxinit.IsOk() )
- return 0; // failed to init wx
- // Signal run_wx_gui_from_dll() that it can continue
- pthread_mutex_lock(&hMutex);
- wxInitialized = true;
- pthread_cond_signal(&hEvent);
- pthread_mutex_unlock(&hMutex);
- // Run the app:
- puts("applauncher: calling wxEntry");
- int argc = 0;
- wxEntry(argc, (wxChar**)NULL);
- pthread_exit(NULL);
- }
- } // anonymous namespace
- // ----------------------------------------------------------------------------
- // public DLL interface
- // ----------------------------------------------------------------------------
- extern "C"
- {
- void run_wx_gui_from_dll(const char *title)
- {
- // In order to prevent conflicts with hosting app's event loop, we
- // launch wx app from the DLL in its own thread.
- //
- // We can't even use wxInitializer: it initializes wxModules and one of
- // the modules it handles is wxThread's private module that remembers
- // ID of the main thread. But we need to fool wxWidgets into thinking that
- // the thread we are about to create now is the main thread, not the one
- // from which this function is called.
- //
- // Note that we cannot use wxThread here, because the wx library wasn't
- // initialized yet. wxCriticalSection is safe to use, though.
- wxCriticalSectionLocker lock(gs_wxStartupCS);
- if ( !mainThreadStarted )
- {
- pthread_attr_t attr;
- pthread_mutex_init(&hMutex, NULL);
- pthread_cond_init(&hEvent, NULL);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- int err = pthread_create(&gs_wxMainThread, &attr, &MyAppLauncher, NULL);
- pthread_attr_destroy(&attr);
- if ( err )
- {
- pthread_mutex_destroy(&hMutex);
- pthread_cond_destroy(&hEvent);
- puts("run: failed to create gs_wxMainThread");
- return; //error
- }
- mainThreadStarted = true;
- pthread_mutex_lock(&hMutex);
- while (!wxInitialized) {
- puts("run: wait for wx to init");
- pthread_cond_wait(&hEvent, &hMutex);
- }
- pthread_mutex_unlock(&hMutex);
- pthread_cond_destroy(&hEvent);
- }
- // Send a message to wx thread to show a new frame:
- wxThreadEvent *event =
- new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);
- event->SetString(title);
- wxQueueEvent(wxApp::GetInstance(), event);
- sleep(3);
- }
- void wx_dll_cleanup()
- {
- wxCriticalSectionLocker lock(gs_wxStartupCS);
- if ( !mainThreadStarted ) {
- puts("cleanup: main thread not started");
- return;
- }
- // If wx main thread is running, we need to stop it. To accomplish this,
- // send a message telling it to terminate the app.
- wxThreadEvent *event =
- new wxThreadEvent(wxEVT_THREAD, CMD_TERMINATE);
- wxQueueEvent(wxApp::GetInstance(), event);
- // We must then wait for the thread to actually terminate.
- puts("cleanup: waiting for main thread to finish");
- pthread_join(gs_wxMainThread, NULL);
- pthread_mutex_destroy(&hMutex);
- }
- } // extern "C"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement