Qt 5.2 DLL返回与调用DLL的Application不同的结果

时间:2015-03-27 04:46:25

标签: c++ qt dll

总结:我有一个导出函数的DLL。在这个函数中,我调用QApplication :: allWidgets()返回一个空列表,而如果该函数在应用程序中,则返回一个包含19个项目的列表。

如果我没弄错的话,框架会维护一个静态的项目列表。 allWidgets()函数返回该列表。据我所知,DLL应该与应用程序位于相同的地址空间,这意味着我应该能够从DLL访问所有静态变量。那么为什么函数是在DLL还是应用程序中呢?

这是DLL代码:

------------------------ test.h ----------------

extern "C"  TESTSHARED_EXPORT std::string DllFun();

------------------------ test.cpp --------------

std::string DllFun()
{
   std::stringstream temp;
   QList<QWidget *> list = QApplication::allWidgets();
   temp << "Number of widgets from DLL " << list.size();
   return temp.str();
}

以下是应用程序代码段:

------------------------------ mainwindow.cpp -------------- -

std::string MainWindow::FunInternal()
{
    std::stringstream temp;
    QList<QWidget *> list = QApplication::allWidgets();
    temp << "Number of widgets from Applicaton " << list.size();
    return temp.str();
}

void MainWindow::on_pushButton_clicked()
{    
    typedef std::string (*FunType)();
    HMODULE handle = LoadLibrary(L"Test.dll");
    FunType DllFun = (FunType)GetProcAddress(handle, "DllFun");

    if (Fun)
    {
       std::string DllWidgets      = DllFun();
       std::string InternalWidgets = FunInternal();
       ui->textEdit->append(QString(DllWidgets.c_str()));
       ui->textEdit->append(QString("\n"));
       ui->textEdit->append(QString(InternalWidgets.c_str()));
    }
}

当我点击按钮时,结果是:

DLL 0中的小部件数

来自Applicaton 19的小部件数量


我正在使用Qt 5.2 Mingw 64 Bit。

更新:即使我的问题仍然有效,这是一种似乎有效的解决方法。如果我将函数指针传递给DLL并从DLL调用函数指针,它就像应用程序一样返回19。

正如Chris所指出的,DLL和Application似乎有两个独立的数据部分。 DLL通常无法访问应用程序的数据部分(其中包含GUI的状态信息),除非通过数据接口或指向它的指针。在我的情况下,这是不可能的,因为我的界面是通用的。我试图通过在我的DLL中使用GetProcAddress来推动这一点,但我没有太大的成功,但我认为理论上这应该工作。

我目前的设计是这样的:

------- genwidget.h
class MyWidget
{
public:
    void modifyWidget(HWND id);
}
------- qtwidget.cpp
#include <genwidget.h>
void MyWidget::modifyWidget(HWND id)
{
// find Panel widget
QWidget *widget = find_widget_from_list(id, QApplication::allWidgets())
// do work
} 
------- vcwidget.cpp
#include <genwidget.h>
void MyWidget::modifyWidget(HWND id)
{
// find Panel widget
Panel ^widget = find_widget_from_list(id);
// do work
} 

我认为我必须以下列方式更改我的设计,以便为每个环境提供自己的界面。

------- genwidget.h
class MyWidget
{
public:
    virtual void modifyWidget() = 0;
}
------- qtwidget.h
class QtMyWidget : public MyWidget
{
 public:
    QtMyWidget(QWidget *panel);
    void modifyWidget();
}
------- vcwidget.h
class VcMyWidget : public MyWidget
{
public:
    VcMyWidget(Panel ^panel);
    void modifyWidget();
}

1 个答案:

答案 0 :(得分:1)

首先,我会避免使用std :: string作为DLL的返回值。除非您打算使用相同的编译器(和版本)和stl,否则您很可能无法正确读取该字符串。

其次,问题是QApplication::allWidgets访问私人列表。 allWidgets实现如下:

QWidgetList QApplication::allWidgets()
{
    if (QWidgetPrivate::allWidgets)
        return QWidgetPrivate::allWidgets->toList();
    return QWidgetList();
}

由于您是从DLL调用它,因此尚未创建QWidgetPrivate::allWidgets(您没有在DLL中创建新的QApplication)。关于为什么应用程序中的QApplication未与DLL共享的一个很好的解释是what happens to global and static variables in a shared library.

这些都是问题所在。由于您似乎并不关心是否使用不同版本的库和不同的编译器,因此您可以将QWidgetList传递给DLL。

// In test.h
extern "C"  TESTSHARED_EXPORT std::string DllFun(QWidgetList *list);

// In test.cpp
std::string DllFun(QWidgetList *list)
{
    std::stringstream temp;
    temp << "Number of widgets from DLL " << list.size();
    return temp.str();
}

// mainwindow.cpp
void MainWindow::on_pushButton_clicked()
{    
    typedef std::string (*FunType)();
    HMODULE handle = LoadLibrary(L"Test.dll");
    FunType DllFun = (FunType)GetProcAddress(handle, "DllFun");

    if (Fun)
    {
       QWidgetList all = QApplication::allWidgets();
       std::string DllWidgets      = DllFun(&all);
       std::string InternalWidgets = FunInternal();
       ui->textEdit->append(QString(DllWidgets.c_str()));
       ui->textEdit->append(QString("\n"));
       ui->textEdit->append(QString(InternalWidgets.c_str()));
    }
}