[Solved] Plugin code is executed but nothing is displayed (Windows)



  • Hi all,

    Overview:
    I have a project that I'm working on and everything works as expected in Linux (builds and runs).
    The same project builds fine on Windows (7 x64), with mingw, and the code for my plugin is executed, but nothing is displayed.

    Expected flow:

    Main window (works)

    loads plugins and places in tools menu (works)

    when clicking on a tool it creates an instance and loads the widget in a tab

    This is the interesting part. I placed message boxes in the code and the message boxes appear, but the tab is never displayed. I can add a tab with QTextEdit for its widget for example. But mine is never shown, just executed. However, it is shown on Linux.

    I noticed that on Windows two files are created when I build my plugin, a .dll and a .a, though on Linux there is only a .so.
    I deleted the .a file to see what would happen but nothing changed.

    Differences:
    The main difference is the directory structure.
    On Linux

    • bin/exec
    • bin/tools/plugin.so

    On Windows

    • bin/release/exec
    • bin/release/tools/plugin.dll

    Conclusion:
    Clearly I'm missing something for Windows, but I'm not sure what it is. I think it's odd that the plugin code is loaded and executed properly but nothing is displayed. I also find it odd that I can add tabs to the QTabWidget of the main window, but not tabs with my plugin.
    Again, it all works as expected on Linux.

    If anyone has any suggestions it'd be much appreciated.
    You can view and download the source on GitHub "here":https://github.com/clarkb7/DR-GUI
    EDIT:
    I should probably mention that the plugins are loaded in 'main_window_t::load_tools' in mainwindow.cpp



  • Are you sure your plugin is loaded correctly? You can use the errorString() method of the QPluginLoader class after calling instance() to see if any errors occured. By the way, these lines:
    @
    plugins_dir = QDir(qApp->applicationDirPath());
    plugins_dir.cd("tools");@

    qApp->applicationDirPath() will get you to the executable dir (I think...), aka the bin dir, and your plugin is in "release/tools" on Windows. I don't think it's loaded correctly.



  • Thanks for your reply Guigui.

    [quote author="Guigui" date="1372787822"]You can use the errorString() method of the QPluginLoader class after calling instance() to see if any errors occured.[/quote]

    loader.errorString() reports "unknown error", both on Windows and on Linux.
    So either something is happening in both places and Linux takes care of it, or "unkown error" is reported when there is no error.

    [quote author="Guigui" date="1372787822"]qApp->applicationDirPath() will get you to the executable dir (I think…), aka the bin dir, and your plugin is in “release/tools” on Windows.[/quote]

    On windows I added
    @plugins_dir.cd("release");@

    Though it didn't seem to be making a difference.
    I just used a MessageBox to display 'qApp->applicationDirPath()' and it is 'bin/release'. Which would explain why the above line didn't change anything.

    If it isn't loaded correctly then why does the code execute? (Though somewhat improperly?)



  • I just noticed your plugin implementation inherits from two base classes: tool_interface_t, which seems ok, and_ tool_base_t_ which contains non purely virtual members. I don't think it is legal. Later in your code, you double cast a plugin object to a tool_base_t, which I also don't think it's legal.

    @void
    main_window_t::add_tab(void)
    {
    QAction *action = qobject_cast<QAction *>(sender());
    tool_base_t *tool = qobject_cast<tool_base_t *>(
    qobject_cast<tool_interface_t *>(
    action->parent())->create_instance());
    const QString tool_name = action->text();

    tab_area->addTab(tool, tool_name);
    

    }@

    Your plugin interface implementation should simply stick to a facade to the services it provides. The tool_base_t should be implemented as a seperate class and your plugin could return tool_base_t objects, ie:

    @QObject *create_instance() = 0;@

    would become

    @tool_base_t *create_instance() = 0;@



  • [quote author="Guigui" date="1372793860"] tool_base_t_ which contains non purely virtual members. I don't think it is legal. [/quote]

    Why? tool_base_t contains functions that will be standard across it's children. Though not fully implemented yet, the idea is to avoid having duplicate code in children for common activities.

    [quote author="Guigui" date="1372793860"] Later in your code, you double cast a plugin object to a tool_base_t, which I also don’t think it’s legal.[/quote]

    It's a little hard to see but I'm casting the parent to tool_interface_t, then calling create_instance(), then casting that to tool_base_t. Though your suggestion does make more sense and is easier to understand.
    It also solved the problem! Thank you! Though I'm not sure why, maybe you could explain?

    [quote author="Guigui" date="1372793860"] The tool_base_t should be implemented as a seperate class [/quote]

    What do you mean by this?

    Also, right now both the main program and each plugin needs to have a copy of tool_base.h and tool_base.cpp. How do avoid this duplication but still let each compile?



  • I am not sure how to put this clearly.

    First, the QtPlugin framework requires that a plugin declaration consists only of pure virtual members. It is however not clearly stated what happens on the plugin definition side, and haven't tested this myself.

    Secondly, in your design, the dr_heapstat_t class (which is the plugin from what I understand) inherits both tool_base_t and tool_interface_t (which is the plugin interface). Why not simply have dr_heapstat_t inherit from tool_interface_t and have it's create_instance() function return tool_base_t. This would make the plugin much less heavy, it would simply stick to its interface, would be easier to manage. The plugin would simply be a tool factory.



  • [quote author="Guigui" date="1372858331"]
    First, the QtPlugin framework requires that a plugin declaration consists only of pure virtual members. It is however not clearly stated what happens on the plugin definition side, and haven’t tested this myself.
    [/quote]

    Okay. The idea of tool_base_t was to provide a base to avoid duplicate code in children. It's currently unused though. e.g every plugin/tool should have the path of the file it is examining, so I planned on having such things in tool_base_t.
    Though since it is common I would like to be able to avoid having to package it with every plugin/tool, and just have the plugins/tools use the tool_base_t packaged with main_window_t. Though I am unsure of how to do this.

    [quote author="Guigui" date="1372858331"]
    Secondly, in your design, the dr_heapstat_t class (which is the plugin from what I understand) inherits both tool_base_t and tool_interface_t (which is the plugin interface). Why not simply have dr_heapstat_t inherit from tool_interface_t and have it's create_instance() function return tool_base_t. This would make the plugin much less heavy, it would simply stick to its interface, would be easier to manage. The plugin would simply be a tool factory.[/quote]

    If dr_heapstat_t only inherits from tool_interface_t then there wouldn't be a conversion from dr_heapstat_t to tool_base_t in create_instance(). It would instead have to return tool_interface_t. Which I think I'll do until I decide what to do with tool_base_t.

    Thank you.



  • Hi,

    You might want to take a look to the last two posts on "this thread":http://qt-project.org/forums/viewthread/29292/.

    I encountered the "Unknown error" issue and it seems the error might appear although the plugin is loaded correctly, so your error might lie elsewhere.



  • Thanks,

    It doesn't return false, so it "worked". I changed the system around a little (using some of your advice) and I feel better about it now.

    I think the problem was the convoluted casting, solved now.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.