Added samples/dll for showing how to use wxWidgets to implement
a DLL that is used from another application written with a different toolkit (or different wx version). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62784 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		
							
								
								
									
										313
									
								
								samples/dll/my_dll.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								samples/dll/my_dll.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
			
		||||
/////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Name:        my_dll.cpp
 | 
			
		||||
// Purpose:     Sample showing how to use wx from a DLL
 | 
			
		||||
// Author:      Vaclav Slavik
 | 
			
		||||
// Created:     2009-12-03
 | 
			
		||||
// RCS-ID:      $Id$
 | 
			
		||||
// Copyright:   (c) 2009 Vaclav Slavik
 | 
			
		||||
// Licence:     wxWindows licence
 | 
			
		||||
/////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// ============================================================================
 | 
			
		||||
// declarations
 | 
			
		||||
// ============================================================================
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// headers
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#include "wx/wxprec.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __BORLANDC__
 | 
			
		||||
    #pragma hdrstop
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __WXMSW__
 | 
			
		||||
    #error "This sample is MSW-only"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "wx/app.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 "wx/msw/wrapwin.h"
 | 
			
		||||
 | 
			
		||||
#include <process.h> // for _beginthreadex()
 | 
			
		||||
 | 
			
		||||
#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(wxEVT_IDLE, wxIdleEventHandler(MyDllApp::OnIdle));
 | 
			
		||||
    Connect(CMD_SHOW_WINDOW,
 | 
			
		||||
            wxEVT_COMMAND_THREAD,
 | 
			
		||||
            wxThreadEventHandler(MyDllApp::OnShowWindow));
 | 
			
		||||
    Connect(CMD_TERMINATE,
 | 
			
		||||
            wxEVT_COMMAND_THREAD,
 | 
			
		||||
            wxThreadEventHandler(MyDllApp::OnTerminate));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MyDllApp::OnShowWindow(wxThreadEvent& event)
 | 
			
		||||
{
 | 
			
		||||
    wxFrame *f = new MyDllFrame(NULL, event.GetString());
 | 
			
		||||
    f->Show(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
 | 
			
		||||
{
 | 
			
		||||
    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
 | 
			
		||||
HANDLE gs_wxMainThread = NULL;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//  wx application startup code -- runs from its own thread
 | 
			
		||||
__stdcall unsigned 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.
 | 
			
		||||
 | 
			
		||||
    // We need to pass correct HINSTANCE to wxEntry() and the right value is
 | 
			
		||||
    // HINSTANCE of this DLL, not of the main .exe.
 | 
			
		||||
    //
 | 
			
		||||
    // This method of obtaining DLL's instance handle requires at least
 | 
			
		||||
    // Windows XP/2003. We could also implement DllMain() and remember it from
 | 
			
		||||
    // there, that would work on older systems too.
 | 
			
		||||
    HINSTANCE hInstance;
 | 
			
		||||
    int ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
 | 
			
		||||
                                (LPCTSTR)&MyAppLauncher,
 | 
			
		||||
                                &hInstance);
 | 
			
		||||
    if ( ret == 0 )
 | 
			
		||||
        return 0; // failed to get DLL's handle
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
    HANDLE hEvent = *(static_cast<HANDLE*>(event));
 | 
			
		||||
    if ( !SetEvent(hEvent) )
 | 
			
		||||
        return 0; // failed setting up the mutex
 | 
			
		||||
 | 
			
		||||
    // Run the app:
 | 
			
		||||
    wxEntry(hInstance);
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // anonymous namespace
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// public DLL interface
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
extern "C" WXEXPORT
 | 
			
		||||
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 ( !gs_wxMainThread )
 | 
			
		||||
    {
 | 
			
		||||
        HANDLE hEvent = CreateEvent
 | 
			
		||||
                        (
 | 
			
		||||
                            NULL,  // default security attributes
 | 
			
		||||
                            FALSE, // auto-reset
 | 
			
		||||
                            FALSE, // initially non-signaled
 | 
			
		||||
                            NULL   // anonymous
 | 
			
		||||
                        );
 | 
			
		||||
        if ( !hEvent )
 | 
			
		||||
            return; // error
 | 
			
		||||
 | 
			
		||||
        // NB: If your compiler doesn't have _beginthreadex(), use CreateThread()
 | 
			
		||||
        gs_wxMainThread = (HANDLE)_beginthreadex
 | 
			
		||||
                                  (
 | 
			
		||||
                                      NULL,           // default security
 | 
			
		||||
                                      0,              // default stack size
 | 
			
		||||
                                      &MyAppLauncher,
 | 
			
		||||
                                      &hEvent,        // arguments
 | 
			
		||||
                                      0,              // create running
 | 
			
		||||
                                      NULL
 | 
			
		||||
                                  );
 | 
			
		||||
 | 
			
		||||
        if ( !gs_wxMainThread )
 | 
			
		||||
        {
 | 
			
		||||
            CloseHandle(hEvent);
 | 
			
		||||
            return; // error
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Wait until MyAppLauncher signals us that wx was initialized. This
 | 
			
		||||
        // is because we use wxMessageQueue<> and wxString later and so must
 | 
			
		||||
        // be sure that they are in working state.
 | 
			
		||||
        WaitForSingleObject(hEvent, INFINITE);
 | 
			
		||||
        CloseHandle(hEvent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send a message to wx thread to show a new frame:
 | 
			
		||||
    wxThreadEvent *event =
 | 
			
		||||
        new wxThreadEvent(wxEVT_COMMAND_THREAD, CMD_SHOW_WINDOW);
 | 
			
		||||
    event->SetString(title);
 | 
			
		||||
    wxQueueEvent(wxApp::GetInstance(), event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern "C" WXEXPORT
 | 
			
		||||
void wx_dll_cleanup(void)
 | 
			
		||||
{
 | 
			
		||||
    wxCriticalSectionLocker lock(gs_wxStartupCS);
 | 
			
		||||
 | 
			
		||||
    if ( !gs_wxMainThread )
 | 
			
		||||
        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_COMMAND_THREAD, CMD_TERMINATE);
 | 
			
		||||
    wxQueueEvent(wxApp::GetInstance(), event);
 | 
			
		||||
 | 
			
		||||
    // We must then wait for the thread to actually terminate.
 | 
			
		||||
    WaitForSingleObject(gs_wxMainThread, INFINITE);
 | 
			
		||||
    CloseHandle(gs_wxMainThread);
 | 
			
		||||
    gs_wxMainThread = NULL;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user