Advertisement
Guest User

my_dll.cpp

a guest
Oct 16th, 2013
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.28 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. #ifdef __BORLANDC__
  21.     #pragma hdrstop
  22. #endif
  23.  
  24. #ifndef __WINDOWS__
  25.     #error "This sample is Windows-only"
  26. #endif
  27.  
  28. #include "wx/app.h"
  29. #include "wx/dynlib.h"
  30. #include "wx/frame.h"
  31. #include "wx/panel.h"
  32. #include "wx/sizer.h"
  33. #include "wx/stattext.h"
  34. #include "wx/button.h"
  35. #include "wx/thread.h"
  36. #include "wx/msgdlg.h"
  37. #include "wx/msw/wrapwin.h"
  38.  
  39. #include <process.h> // for _beginthreadex()
  40.  
  41. #include "my_dll.h"
  42.  
  43. // ----------------------------------------------------------------------------
  44. // GUI classes
  45. // ----------------------------------------------------------------------------
  46.  
  47. class MyDllFrame : public wxFrame
  48. {
  49. public:
  50.     MyDllFrame(wxWindow *parent, const wxString& label);
  51.  
  52.     void OnAbout(wxCommandEvent& event);
  53.  
  54.     DECLARE_EVENT_TABLE()
  55. };
  56.  
  57.  
  58. static const int CMD_SHOW_WINDOW = wxNewId();
  59. static const int CMD_TERMINATE = wxNewId();
  60.  
  61. class MyDllApp : public wxApp
  62. {
  63. public:
  64.     MyDllApp();
  65.  
  66. private:
  67.     void OnShowWindow(wxThreadEvent& event);
  68.     void OnTerminate(wxThreadEvent& event);
  69. };
  70.  
  71.  
  72. // ============================================================================
  73. // implementation
  74. // ============================================================================
  75.  
  76. // ----------------------------------------------------------------------------
  77. // MyDllFrame
  78. // ----------------------------------------------------------------------------
  79.  
  80. BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
  81.     EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
  82. END_EVENT_TABLE()
  83.  
  84. MyDllFrame::MyDllFrame(wxWindow *parent, const wxString& label)
  85.     : wxFrame(parent, wxID_ANY, label)
  86. {
  87.     wxPanel *p = new wxPanel(this, wxID_ANY);
  88.     wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
  89.  
  90.     sizer->Add
  91.            (
  92.                new wxStaticText
  93.                    (
  94.                        p, wxID_ANY,
  95.                        wxString::Format
  96.                        (
  97.                            "Running using %s\n"
  98.                            "wxApp instance is %p, thread ID %ld",
  99.                            wxVERSION_STRING,
  100.                            wxApp::GetInstance(),
  101.                            wxThread::GetCurrentId()
  102.                        )
  103.                    ),
  104.                wxSizerFlags(1).Expand().Border(wxALL, 10)
  105.            );
  106.  
  107.     sizer->Add
  108.            (
  109.                new wxButton(p, wxID_ABOUT, "Show info"),
  110.                wxSizerFlags(0).Right().Border(wxALL, 10)
  111.            );
  112.  
  113.     p->SetSizerAndFit(sizer);
  114.  
  115.     wxSizer *fsizer = new wxBoxSizer(wxVERTICAL);
  116.     fsizer->Add(p, wxSizerFlags(1).Expand());
  117.     SetSizerAndFit(fsizer);
  118. }
  119.  
  120. void MyDllFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  121. {
  122.     wxMessageBox("This window is running in its own thread,\n"
  123.                  "using private wxWidgets instance compiled into the DLL.",
  124.                  "About",
  125.                  wxOK | wxICON_INFORMATION);
  126. }
  127.  
  128.  
  129. // ----------------------------------------------------------------------------
  130. // MyDllApp
  131. // ----------------------------------------------------------------------------
  132.  
  133. MyDllApp::MyDllApp()
  134. {
  135.     // Keep the wx "main" thread running even without windows. This greatly
  136.     // simplifies threads handling, because we don't have to correctly
  137.     // implement wx-thread restarting.
  138.     //
  139.     // Note that this only works if you don't explicitly call ExitMainLoop(),
  140.     // except in reaction to wx_dll_cleanup()'s message. wx_dll_cleanup()
  141.     // relies on the availability of wxApp instance and if the event loop
  142.     // terminated, wxEntry() would return and wxApp instance would be
  143.     // destroyed.
  144.     //
  145.     // Also note that this is efficient, because if there are no windows, the
  146.     // thread will sleep waiting for a new event. We could safe some memory
  147.     // by shutting the thread down when it's no longer needed, though.
  148.     SetExitOnFrameDelete(false);
  149.  
  150.     Connect(CMD_SHOW_WINDOW,
  151.             wxEVT_THREAD,
  152.             wxThreadEventHandler(MyDllApp::OnShowWindow));
  153.     Connect(CMD_TERMINATE,
  154.             wxEVT_THREAD,
  155.             wxThreadEventHandler(MyDllApp::OnTerminate));
  156. }
  157.  
  158. void MyDllApp::OnShowWindow(wxThreadEvent& event)
  159. {
  160.     wxFrame *f = new MyDllFrame(NULL, event.GetString());
  161.     f->Show(true);
  162. }
  163.  
  164. void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
  165. {
  166.     ExitMainLoop();
  167. }
  168.  
  169.  
  170. // ----------------------------------------------------------------------------
  171. // application startup
  172. // ----------------------------------------------------------------------------
  173.  
  174. // we can't have WinMain() in a DLL and want to start the app ourselves
  175. IMPLEMENT_APP_NO_MAIN(MyDllApp)
  176.  
  177. namespace
  178. {
  179.  
  180. // Critical section that guards everything related to wxWidgets "main" thread
  181. // startup or shutdown.
  182. wxCriticalSection gs_wxStartupCS;
  183. // Handle of wx "main" thread if running, NULL otherwise
  184. HANDLE gs_wxMainThread = NULL;
  185.  
  186.  
  187. //  wx application startup code -- runs from its own thread
  188. unsigned wxSTDCALL MyAppLauncher(void* event)
  189. {
  190.     // Note: The thread that called run_wx_gui_from_dll() holds gs_wxStartupCS
  191.     //       at this point and won't release it until we signal it.
  192.  
  193.     // We need to pass correct HINSTANCE to wxEntry() and the right value is
  194.     // HINSTANCE of this DLL, not of the main .exe, use this MSW-specific wx
  195.     // function to get it. Notice that under Windows XP and later the name is
  196.     // not needed/used as we retrieve the DLL handle from an address inside it
  197.     // but you do need to use the correct name for this code to work with older
  198.     // systems as well.
  199.     const HINSTANCE
  200.         hInstance = wxDynamicLibrary::MSWGetModuleHandle("my_dll",
  201.                                                          &gs_wxMainThread);
  202.     if ( !hInstance )
  203.         return 0; // failed to get DLL's handle
  204.  
  205.     // IMPLEMENT_WXWIN_MAIN does this as the first thing
  206.     wxDISABLE_DEBUG_SUPPORT();
  207.  
  208.     // We do this before wxEntry() explicitly, even though wxEntry() would
  209.     // do it too, so that we know when wx is initialized and can signal
  210.     // run_wx_gui_from_dll() about it *before* starting the event loop.
  211.     wxInitializer wxinit;
  212.     if ( !wxinit.IsOk() )
  213.         return 0; // failed to init wx
  214.  
  215.     // Signal run_wx_gui_from_dll() that it can continue
  216.     HANDLE hEvent = *(static_cast<HANDLE*>(event));
  217.     if ( !SetEvent(hEvent) )
  218.         return 0; // failed setting up the mutex
  219.  
  220.     // Run the app:
  221.     wxEntry(hInstance);
  222.  
  223.     return 1;
  224. }
  225.  
  226. } // anonymous namespace
  227.  
  228. // ----------------------------------------------------------------------------
  229. // public DLL interface
  230. // ----------------------------------------------------------------------------
  231.  
  232. extern "C"
  233. {
  234.  
  235. void run_wx_gui_from_dll(const char *title)
  236. {
  237.     // In order to prevent conflicts with hosting app's event loop, we
  238.     // launch wx app from the DLL in its own thread.
  239.     //
  240.     // We can't even use wxInitializer: it initializes wxModules and one of
  241.     // the modules it handles is wxThread's private module that remembers
  242.     // ID of the main thread. But we need to fool wxWidgets into thinking that
  243.     // the thread we are about to create now is the main thread, not the one
  244.     // from which this function is called.
  245.     //
  246.     // Note that we cannot use wxThread here, because the wx library wasn't
  247.     // initialized yet. wxCriticalSection is safe to use, though.
  248.  
  249.     wxCriticalSectionLocker lock(gs_wxStartupCS);
  250.  
  251.     if ( !gs_wxMainThread )
  252.     {
  253.         HANDLE hEvent = CreateEvent
  254.                         (
  255.                             NULL,  // default security attributes
  256.                             FALSE, // auto-reset
  257.                             FALSE, // initially non-signaled
  258.                             NULL   // anonymous
  259.                         );
  260.         if ( !hEvent )
  261.             return; // error
  262.  
  263.         // NB: If your compiler doesn't have _beginthreadex(), use CreateThread()
  264.         gs_wxMainThread = (HANDLE)_beginthreadex
  265.                                   (
  266.                                       NULL,           // default security
  267.                                       0,              // default stack size
  268.                                       &MyAppLauncher,
  269.                                       &hEvent,        // arguments
  270.                                       0,              // create running
  271.                                       NULL
  272.                                   );
  273.  
  274.         if ( !gs_wxMainThread )
  275.         {
  276.             CloseHandle(hEvent);
  277.             return; // error
  278.         }
  279.  
  280.         // Wait until MyAppLauncher signals us that wx was initialized. This
  281.         // is because we use wxMessageQueue<> and wxString later and so must
  282.         // be sure that they are in working state.
  283.         WaitForSingleObject(hEvent, INFINITE);
  284.         CloseHandle(hEvent);
  285.     }
  286.  
  287.     // Send a message to wx thread to show a new frame:
  288.     wxThreadEvent *event =
  289.         new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);
  290.     event->SetString(title);
  291.     wxQueueEvent(wxApp::GetInstance(), event);
  292. }
  293.  
  294. void wx_dll_cleanup()
  295. {
  296.     wxCriticalSectionLocker lock(gs_wxStartupCS);
  297.  
  298.     if ( !gs_wxMainThread )
  299.         return;
  300.  
  301.     // If wx main thread is running, we need to stop it. To accomplish this,
  302.     // send a message telling it to terminate the app.
  303.     wxThreadEvent *event =
  304.         new wxThreadEvent(wxEVT_THREAD, CMD_TERMINATE);
  305.     wxQueueEvent(wxApp::GetInstance(), event);
  306.  
  307.     // We must then wait for the thread to actually terminate.
  308.     WaitForSingleObject(gs_wxMainThread, INFINITE);
  309.     CloseHandle(gs_wxMainThread);
  310.     gs_wxMainThread = NULL;
  311. }
  312.  
  313. } // extern "C"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement