Russian Qt Forum

Qt => ActiveX => Тема начата: kirill от Май 05, 2010, 15:16



Название: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 05, 2010, 15:16
Прошу помощи!
Сделал сервер
Код
C++ (Qt)
// .h
class AxRoll : public QMainWindow, public QAxBindable
// .cpp
#include <QAxFactory>
QAXFACTORY_DEFAULT(AxRoll,
                  "{FD11A5A4-B433-49e1-A0E5-40496D16EC0B}",
                  "{D1A36ABB-16AE-4cd1-BAEE-D7C77F1F80EA}",
                  "{4CD7F9AF-BDAC-4e21-A2C4-291102674DF8}",
                  "{DD5F39F0-AA74-4441-8F4E-A1E26F97A88A}",
                  "{CB2FD6FF-E56A-4e76-ABE4-741066BF70AA}")
 
AxRoll::AxRoll(QWidget * w)
: QMainWindow(w)
{
  setCentralWidget(new QLabel("TEST LABEL", this));
}
 

Поместил его в dll

Код:
CONFIG += dll qaxserver

Соответственно сделал клиента в .exe
Код
C++ (Qt)
{
  QAxWidget * rollWidget = new QAxWidget;
  rollWidget->setControl("{FD11A5A4-B433-49e1-A0E5-40496D16EC0B}");
  rollWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
  QVBoxLayout * vl = new QVBoxLayout;
  vl->setSizeConstraint(QLayout::SetMinAndMaxSize);
  vl->addWidget(rollWidget);
  setLayout(vl);
}
 

ВСЕ чудесно работает.
Переношу клиента в dll и делаю exe, использующий эту dll.
Все точно также прекрасно работает. НО! При выходе из приложения процесс exe остается висеть в памяти. Чего не было на связке dll(сервер) — exe(клиент). А на связке dll(сервер) — dll(клиент) — exe похоже не выгружается dll(клиент).

Как такое побороть?
dll(клиент) линкуется к exe статически через .lib файл.
Ппробовал загружать клиентскую dll динамически и делать ей unload() — не помогает...


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 06, 2010, 07:01
А под чем компилишь?
У меня в Qt Creator как-то "неохотно" это все компилилось, а в MS VS + Qt "на ура".


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 07:23
А под чем компилишь?
У меня в Qt Creator как-то "неохотно" это все компилилось, а в MS VS + Qt "на ура".

MS VS + Qt


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 06, 2010, 08:08
А что если подгружать dll клиента явно и при окончании работы делать ей FreeLibrary() или __FUnloadDelayLoadedDLL()


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 08:34
А что если подгружать dll клиента явно и при окончании работы делать ей FreeLibrary() или __FUnloadDelayLoadedDLL()

Ппробовал загружать клиентскую dll динамически и делать ей unload() — не помогает...


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 06, 2010, 11:00
Стоп.
А подгружаешь по средствам QLibrary?
Может имеет смысл через виндовые LoadLibrary?
Не знаю поможет ли, но как вариант ...


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 14:24
Стоп.
А подгружаешь по средствам QLibrary?
Может имеет смысл через виндовые LoadLibrary?
Не знаю поможет ли, но как вариант ...

Блин уже крыша едет.

Сделал так.
В dll - сервер.
Из exe вызываю.
Так вот если вызывать сервер из конструктора вот так
Код
C++ (Qt)
MainWindow::MainWindow(QWidget * parent)
: QMainWindow(parent)
{
  QAxWidget * wid = new QAxWidget;
  wid->setControl("{E437F37D-53BC-4d2c-97BD-31BC413204F9}");
  wid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  setCentralWidget(wid);
}
 

То все работает и при выходе процесс успешно завершается.
Но вот если я стану создавать ActiveX не в конструкторе, а в каком нибудь слоте, то процесс не завершается.
То есть
Код
C++ (Qt)
MainWindow::MainWindow(QWidget * parent)
: QMainWindow(parent)
{
  setCentralWidget(new QWidget(this));
}
//некий slot
void MainWindow::newFile()
{
  QAxWidget * wid = new QAxWidget;
  wid->setControl("{E437F37D-53BC-4d2c-97BD-31BC413204F9}");
  wid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  wid->show();
}
 

То тогда при приложение не завершается при закрытии.
a.setQuitOnLastWindowClosed(true); ставил
setAttribute(Qt::WA_DeleteOnClose); тоже ставил

чо за нафиг. ничо не понимаю


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 06, 2010, 14:43
Эм ... по приведенным примерам плохо понял(у меня тоже голова кипит), но такое чувство, что просто когда ты делаешь в конструкторе setCentralWidget(wid), то QMainWindow запоминает ссылку на wid и при вызове деструктора неявно удаляет объект. А когда ты делаешь в слоте, то QAxWidget * wid = new QAxWidget просто создает объект в памяти и по завершении работы функции/слота переменная wid грохается, а с ней и вся информация по тому где ж теперь новоиспеченный QAxWidget.
Выйти мона следующим образом:
Код:
class MainWindow: public QMainWindow
{
pablic:
  QAxWidget *wid;
}
/*
тили, тили, трали-вали: создали, вызвали
*/
MainWindow::~MainWindow(
  delete wid;
)


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: BRE от Май 06, 2010, 14:44
Попробуй задавать parent.
Код
C++ (Qt)
void MainWindow::newFile()
{
  QAxWidget * wid = new QAxWidget( this );
  ...
}
 

или попробуй принудительно удалять объект.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 15:00
Попробуй задавать parent.
Код
C++ (Qt)
void MainWindow::newFile()
{
  QAxWidget * wid = new QAxWidget( this );
  ...
}
 

или попробуй принудительно удалять объект.


Задавал парента, удалял руками, увы, процесс остается в памяти.
То есть, я закрываю главное окно (установлено a.setQuitOnLastWindowClosed(true);) и смотрю в деструктор не приходим.
Ладно, ставлю тогда главному окну setAttribute(Qt::WA_DeleteOnClose);
Вылетает алерт
Код:
HEAP[ActiveQtClient_d.exe]: Invalid Address specified to RtlValidateHeap( 00B20000, 0012FE98 )
Windows has triggered a breakpoint in ActiveQtClient_d.exe.

This may be due to a corruption of the heap, and indicates a bug in ActiveQtClient_d.exe or any of the DLLs it has loaded.


То есть пишет что возможно не выгружена dll.
Чем можно посмотреть, что держит процесс и не дает ему закрыться?
Я конечно могу прибивать по exit(0) но это не наш путь, надо понять что происходит


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 15:05
Эм ... по приведенным примерам плохо понял(у меня тоже голова кипит), но такое чувство, что просто когда ты делаешь в конструкторе setCentralWidget(wid), то QMainWindow запоминает ссылку на wid и при вызове деструктора неявно удаляет объект. А когда ты делаешь в слоте, то QAxWidget * wid = new QAxWidget просто создает объект в памяти и по завершении работы функции/слота переменная wid грохается, а с ней и вся информация по тому где ж теперь новоиспеченный QAxWidget.
Выйти мона следующим образом:
Код:
class MainWindow: public QMainWindow
{
pablic:
  QAxWidget *wid;
}
/*
тили, тили, трали-вали: создали, вызвали
*/
MainWindow::~MainWindow(
  delete wid;
)

Это я пробовал, но не помогло.

В случае создания activeX в конструкторе деструктор нормально вызывается, и объект уничтожается.
А если я делаю создание activeX через слот, то при закрытии главного окна деструктор вообще не вызывается.
Тогда я ставлю setAttribute(Qt::WA_DeleteOnClose); главному окну и тогда программа просто грохается.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 15:15
Кинул минимальный пример кода с проектами.
ActiveQtServer - сервер
ActiveQtClient - клиент



Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 06, 2010, 15:47
Я правильно понял, просто вызывать второй слот где делается delete wid пробовал, но не помогло?


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 06, 2010, 17:22
Я правильно понял, просто вызывать второй слот где делается delete wid пробовал, но не помогло?
Да да, во втором слоте вручную удаляю, но не помогает. Деструктор MainWindow не вызывается.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: BRE от Май 06, 2010, 17:54
Деструктор MainWindow не вызывается.
Так проблема в том, что не вызывается деструктор MainWindow?
А если "руками" удалить объект QAxWidget, то все нормально выгружается?


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 07, 2010, 05:54
Деструктор MainWindow не вызывается.
Так проблема в том, что не вызывается деструктор MainWindow?
А если "руками" удалить объект QAxWidget, то все нормально выгружается?


В общем так.
В класса MainWindow в протектед - указатель на QAxWidget.
Один слот создает экземпляр QAxWidget, второй удаляет. Дальше пытаюсь закрыть главное окно крестиком и вижу, что в деструктрор MainWindow мы не приходим. Окно тем не менее скрывается, но процесс остается в памяти и студия ждет его завершения. Приходится останавливать дебаг руками.

Далее, если я создам экземпляр QAxWidget в конструкторе MainWindow и установлю его в качестве центрального виджета, то закрытие по крестику главного окна вызовет деструктор и процесс нормально завершится.

Я от такого поведения в замешательстве.


Добавлю еще следующую вещь. В качестве ActiveX сервера создается опять же главное окно. То есть получаем главное окно вложенное в другое главное окно во втором случае, а в первом - из главного окна создается новое главное окно.
Подозреваю, что проблема в том, что новое главное окно имеет свой цикл обработки сообщений и он не завершается. Но это так, предположение.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: Sanya от Май 07, 2010, 06:33
Я в Qt недавно, но уже тоже по сталкивался с непонятным мне(возможно пока) поведением сигналов.
А если такое шаманство:
В конструкторе QMainWindow в центр поставить некоторый контейнер, допустим QWidget и создать. А вот уже в него встроить AxServer.
P.S.:
   Взять прям код и погонять мне тяжко - работы выше крыши, сорри.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: BRE от Май 07, 2010, 07:52
Дальше пытаюсь закрыть главное окно крестиком и вижу, что в деструктрор MainWindow мы не приходим.
Код
C++ (Qt)
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
...
MainWindow mw;
mw.show()
 
return app.exec();
}
 
В этом случае деструктор MainWindow будет вызываться.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: kirill от Май 07, 2010, 10:23
Дальше пытаюсь закрыть главное окно крестиком и вижу, что в деструктрор MainWindow мы не приходим.
Код
C++ (Qt)
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
...
MainWindow mw;
mw.show()
 
return app.exec();
}
 
В этом случае деструктор MainWindow будет вызываться.


хм.. именно так и делаю.
Это вроде как стандартная схема.


Название: Re: ActiveQt - сервер и клиент в dll
Отправлено: sy от Май 27, 2010, 15:41
Я не очень уверен, что это связано с данной темой, но сегодня наткнулся на загадочное поведение
void QAxBase::internalRelease()
утилита dumpcpp вставляет эту процедуру в конструкторе класса-переходника к интерфейсу COM-сервера:
Код:
class PCKERNEL_EXPORT ITask : public QAxObject
{
public:
    ITask(IDispatch *subobject = 0, QAxObject *parent = 0)
    : QAxObject((IUnknown*)subobject, parent)
    {
         internalRelease();
    }
...
Так вот, если вызов этой функции отключить, то нарушений(скорее всего в стеке) в клиенте не происходит (не разваливается в непредсказуемых местах).