wxDialog from two dll's is causing event to disappear

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

We have two dlls (dynamic library) and each dll has a wxwidgets dialog function which shows the GUI.

The dll works as follows:
1. It initializes the wxwidgets in a separate thread which keeps running until the dialog is closed.

Code: Select all

CODE: SELECT ALL

static const int CMD_SHOW_WINDOW = wxNewId();

class MyDllApp : public wxApp
{
public:
    MyDllApp();

private:
    void OnShowWindow(wxThreadEvent& event);

};

void MyDllApp::OnShowWindow(wxThreadEvent& event)
{
    myDialog dlg(_( "Show sample dialog" ));
    dlg.ShowModal();
}

IMPLEMENT_APP_NO_MAIN(MyDllApp);

//  wx application startup code -- runs from its own thread
unsigned wxSTDCALL MyAppLauncher(void* event)
{
#ifdef WIN32
    const HINSTANCE
        hInstance = wxDynamicLibrary::MSWGetModuleHandle("my_dll-1 or my_dll-2",
                                                         &gs_wxMainThread);
    if ( !hInstance )
        return 0; // failed to get DLL's handle

    // wxIMPLEMENT_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);
#endif 
    return 1;
}
2. Shows the wxwidgets dialog.

Code: Select all


void MyDllApp::OnShowWindow(wxThreadEvent& event)
{
    CORELOG_PUTSTR_D("OnShowWindow - Function Start");
    PromptCallback(); ==> this creates the wxwidgets dialog 
    CORELOG_PUTSTR_D("OnShowWindow - Function Start");
}

extern "C" WXEXPORT void ShowwxDialog()
{
   wxCriticalSectionLocker lock(gs_wxStartupCS);
   gs_wxMainThread = (HANDLE)_beginthreadex
            (
            NULL,           // default security
            0,              // default stack size
            &MyAppLauncher,
            &hEvent,        // arguments
            0,              // create running
            NULL
            );
   // 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.
 //Note: We are using pthread_create and pthread_signal_wait etc on Linux/MacOS
       WaitForSingleObject(hEvent, INFINITE);
        CloseHandle(hEvent);

// Send a message to wx thread to show a new frame:
    wxThreadEvent *event =
        new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);

   wxQueueEvent(wxApp::GetInstance(), event);
   ....
}
 
3. Closes the thread when dialog is closed.

Code: Select all

 void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
{
    ExitMainLoop();
}


void wx_dll_cleanup()
{
    void *status = NULL;
    int rsts = CSF_STS_OK;
#ifdef WIN32
    DWORD exitCode = CSF_STS_OK;
#endif
    
    wxCriticalSectionLocker lock(gs_wxUserAuthStartupCS);

#if defined(WIN32)
    if ( !gs_wxMainThread ) {
        goto clean_exit;
    }
#endif

    /* 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);

#if defined(WIN32)
    /* We must then wait for the thread to actually terminate. */
    WaitForSingleObject(gs_wxMainThread, INFINITE);
    GetExitCodeThread (gs_wxMainThread, &exitCode);
    CloseHandle(gs_wxMainThread);
    gs_wxMainThread = NULL;
#endif

}
 

These dlls (dll-1 and dll-2) are loaded from some thread party application and same code is there is both the dlls but they show different dialogs.
The dlls are loaded once per process and keep running until the third party application closes or terminates.

It works fine:
1. If dll-1 is loaded to show the dialog multiple times without closing the third party applicaiton, it shows properly any number of times.
2. If dll-2 is loaded to show the dialog multiple times without closing the third party applicaiton, it shows properly any number of times.

Issue occurs when following sequence of steps are performed:
1. Load dll-1 and show the dialog and close the dialog.
2. Load dll-2 and show the dialog and close the dialog.
3. When we try to show the dialog of dll-1 the event to show CMD_SHOW_WINDOW is not getting triggered and UI is not shown. However when dialog from dll-2 is called, it shows the UI properly.

Maybe when dll-2 is called the main thread is not getting cleaned up or all the events are going to only dll-2 once dll-2 is used?

Can you please help to fix this issue?

The issue is reported on Windows 10.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxDialog from two dll's is causing event to disappear

Post by ONEEYEMAN »

Hi,
What happen if you try to show dialog2 first then dialog1?
When the dialog is closed - does dll unloads/thread finishes?

Thank you.
User avatar
doublemax@work
Super wx Problem Solver
Super wx Problem Solver
Posts: 474
Joined: Wed Jul 29, 2020 6:06 pm
Location: NRW, Germany

Re: wxDialog from two dll's is causing event to disappear

Post by doublemax@work »

Does the main app use wxWidgets?
How do you link to wxWidgets, statically or dynamically?

I suspect that the main app does not use wx and that the DLLs link dynamically to wx. That means both DLLs "talk" to the same wxWidgets instance. Each DLL will initialize and uninitialize wxWIdgets without knowing about the other DLL. You'll need some mechanism to prevent that one DLL uninitializes wxWidgets while another DLL is still open.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxDialog from two dll's is causing event to disappear

Post by ONEEYEMAN »

Hi,
I'm also curious - why do you need 2 dlls with 2 different threads for 2 dialogs?

Can't you put both dialogs inside the same DLL/so/dylib and just call them as needed?

On top of that the number of thread will be reduced as you will not need a dedicated thread for every dialog.

Thank you.
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

Thank you for the response.
ONEEYEMAN wrote: Wed Aug 03, 2022 11:55 am Hi,
What happen if you try to show dialog2 first then dialog1?
When the dialog is closed - does dll unloads/thread finishes?

Thank you.
I get the same issue irrespective of the order.
We only load the dll's once per process and unload them only when the application exits.
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

doublemax@work wrote: Wed Aug 03, 2022 2:20 pm Does the main app use wxWidgets?
How do you link to wxWidgets, statically or dynamically?

I suspect that the main app does not use wx and that the DLLs link dynamically to wx. That means both DLLs "talk" to the same wxWidgets instance. Each DLL will initialize and uninitialize wxWIdgets without knowing about the other DLL. You'll need some mechanism to prevent that one DLL uninitializes wxWidgets while another DLL is still open.
No, the main app doesn't use wxwidgets. It uses Java/MFC on windows. We link to wxwidgets dynamically and not statically.
Yes, dll's talk to wxwidgets instance - correct.
Yes, each DLL's will initialize and uninitialize/cleanup without knowing about the other DLL. The threads are terminated gracefully by calling ExitMainLoop().

Yes, need some suggessions here as I cannot move the UI of one dll into another or merge both into one as they are shipped differently and perform different activities. They are needed together in few scenarios.
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

ONEEYEMAN wrote: Wed Aug 03, 2022 3:47 pm Hi,
I'm also curious - why do you need 2 dlls with 2 different threads for 2 dialogs?

Can't you put both dialogs inside the same DLL/so/dylib and just call them as needed?

On top of that the number of thread will be reduced as you will not need a dedicated thread for every dialog.

Thank you.
Yes, I understand the suggestion but we have to use differnet dlls as they are shipped differently and handle different functionality.

How about creating one main thread to listen on the wxwidget events and let these two dll's call this and link statically in each code. we can declare global static and initialize it only once per process and keep running until the application is closed?
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxDialog from two dll's is causing event to disappear

Post by ONEEYEMAN »

Hi,
Yes, I understand the suggestion but we have to use differnet dlls as they are shipped differently and handle different functionality.

How about creating one main thread to listen on the wxwidget events and let these two dll's call this and link statically in each code. we can declare global static and initialize it only once per process and keep running until the application is closed?
No you don't have to.
Yu are writing both DLLs, correct?
Which means you decide how it shipped.

The DLL/ dialogs can perform different task. There is no problem with that. In fact in my code I have 1 DLL/so/dylib that contains multiple completely different and completely unrelated dialogs. This library is being loaded on demand when the dialog is needed. And when the dialog is closed with OK/Cancel the library is unloaded.
Did you try that solution? If it works you can change how the DLL will ship. Moreover - if you application is a plugin with multiple dialogs I'd say that there should be only one method to ship it - make an installer, so that the user can install the library and be done with it.

Will make your life so much easier.
KISS principle.

Thank you.

BTW, the way the final product is developed to the customer shouldn't dictate how the application is designed. It should be other way around.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxDialog from two dll's is causing event to disappear

Post by doublemax »

Sridhar@Work wrote: Thu Aug 04, 2022 5:22 am Yes, need some suggessions here as I cannot move the UI of one dll into another or merge both into one as they are shipped differently and perform different activities. They are needed together in few scenarios.
If the two DLLs don't communicate with each other at all, the easiest way may be to just link wxWidgets statically to each DLL.
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

ONEEYEMAN wrote: Thu Aug 04, 2022 5:33 am
No you don't have to.
Yu are writing both DLLs, correct?
Which means you decide how it shipped.
Yes. There is other part of the code in the same DLL which is linked to functionality of the UI. So, changing the DLL's would not be a option for us.
I completely understand your suggestion. However, I can try that as a last option when none of the other suggestions are working. I'm trying to understand the issue for such scenario so it can be fixed.
ONEEYEMAN wrote: Thu Aug 04, 2022 5:33 am
The DLL/ dialogs can perform different task. There is no problem with that. In fact in my code I have 1 DLL/so/dylib that contains multiple completely different and completely unrelated dialogs. This library is being loaded on demand when the dialog is needed. And when the dialog is closed with OK/Cancel the library is unloaded.
Did you try that solution? If it works you can change how the DLL will ship. Moreover - if you application is a plugin with multiple dialogs I'd say that there should be only one method to ship it - make an installer, so that the user can install the library and be done with it.
DLL is not plugin and we load dll's only once per process and unload it only when the application exits as it is integrated with another third party application. We also need to show this UI multiple times so cannot load/unload each time.

Did any one face similar issues?

Note: The code works fine on linux/macOS.

It is using

Code: Select all

..
#if defined (WIN32)
const HINSTANCE hInstance = wxDynamicLibrary::MSWGetModuleHandle("<dllname>", &gs_wxMainThread);
wxInitializer wxinit;
wxEntry(hInstance);
#else /* macOS/Linux */
wxInitializer wxinit;
wxApp *mydllapp = new MyDllApp;
wxApp::SetInstance( mydllapp );
wxEntry(argc,static_cast<wxChar**>(NULL));
#endif
Any issue with wxEntry(...)? Is the approach correct for Windows?
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

I'm using 3.1.7 wxwidgets release version. So for this version, is this the correct approach to initialize wxwidgets to run in thread on Windows?

Code: Select all

Threadcode () {
...
const HINSTANCE hInstance = wxDynamicLibrary::MSWGetModuleHandle("<dllname>", &gs_wxMainThread);
wxInitializer wxinit;
wxEntry(hInstance);
}
When I'm using same release version of wxwidgets on Linux, with the wxwidgets thread initialization code as below - The code works without issues.

Code: Select all

wxInitializer wxinit;
wxApp *mydllapp = new MyDllApp;
wxApp::SetInstance( mydllapp );
wxEntry(argc,static_cast<wxChar**>(NULL));
On macOS, we use dispath_sync(..async..calls) so we don't need to worry about the threading etc. It works smoothly without any threads using dispatch_sync().
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

I found the link: https://wiki.wxwidgets.org/Creating_A_D ... UI_support where the initiazation works quite differently for different release. Is there something changed in latest version so it needs to be initialized as

Code: Select all

WORD WINAPI ThreadProc(LPVOID lpParameter)
{
    wxApp::SetInstance(new wxDLLApp());
    wxEntry(GetModuleHandle(NULL), NULL, NULL, SW_SHOW);
    return true;
}


Please suggest!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

When I used the following change, the code worked smoothly on Windows, macOS and Linux:

Code: Select all

class MyDllApp : public wxApp
{
public:
    MyDllApp();
    ~MyDllApp();

private:
    void OnShowWindow(wxThreadEvent& event);
    void OnTerminate(wxThreadEvent& event);
    void OnMessageBox(wxThreadEvent& event);
};

thread ()
{
....
#if defined(WIN32)
        const HINSTANCE hInstance = wxDynamicLibrary::MSWGetModuleHandle("mydll", &gs_wxMainThread);
        wxInitializer wxinit;
        /* Run the app: */
        wxApp *mydllapp = new MyDllApp;
        wxApp::SetInstance( mydllapp );
        wxEntry(hInstance, NULL, NULL, SW_SHOW);
#else
        /* Run the app: */
        wxApp *mydllapp = new MyDllApp;
        wxApp::SetInstance( mydllapp );
        wxEntry(argc,static_cast<wxChar**>(NULL));
#endif
...
}
Hope this helps others!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: wxDialog from two dll's is causing event to disappear

Post by Sridhar@Work »

Hi Friends

Is there anything wrong using this code on Windows? I see memory leak for not deleting the MyDllApp pointer? If I delete the pointer, the program crashes. So I assume wxWidgets takes care of deleting the pointer. Some from community suggest using this method and other say it is not needed. Little confused what is the best approach.!

Any suggestions or help here would be appreciated!
Post Reply