Russian Qt Forum
Май 03, 2024, 08:20 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла  (Прочитано 9181 раз)
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« : Март 18, 2012, 20:26 »

Здравствуйте. Есть win/mac приложение, которое регистрируется дефолтным для определенного типа файлов. Если открыть такой файл когда программа не запущена, то под виндой никаких проблем нет: файл передается в argv, и можно передать его в конструктор и сразу показать именно его.

В мак ос же файл передается через QFileOpenEvent, который приходит только после вызова app.exec(), потому программа сначала показывает пустое окно (или последний использованый файл, если соответствующая опция включена), а только потом грузит открытый файл. Это было бы не так страшно (файлы грузятся быстро), если бы не один противный момент: при загрузке файла программа может показать какое-нибудь уведомление через статический метод QMessageBox (именно при распарсивании файла), и если такое уведомление было показано для последнего использованного файла, то в момент загрузки "щелкнутого" файла программа крашит.

Привожу на всякий случай бэктрэйс:
Код:
Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   QtGui                         0x00000001002c72aa QWidget::isWindowModified() const + 4
1   com.kambala.MedianXLOfflineTools 0x0000000100006ce2 MedianXLOfflineTools::maybeSave() + 34 (medianxlofflinetools.cpp:2170)
2   com.kambala.MedianXLOfflineTools 0x00000001000067db MedianXLOfflineTools::loadFile(QString const&) + 299 (medianxlofflinetools.cpp:86)
3   com.kambala.MedianXLOfflineTools 0x000000010009e1fa Application::event(QEvent*) + 106 (application.cpp:84)
4   QtGui                         0x0000000100287be8 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 304
5   QtGui                         0x0000000100287e66 QApplication::notify(QObject*, QEvent*) + 600
6   QtCore                         0x0000000100f1c982 QCoreApplication::notifyInternal(QObject*, QEvent*) + 104
7   QtGui                         0x000000010028737a qt_sendSpontaneousEvent(QObject*, QEvent*) + 42
8   QtGui                         0x000000010023aad7 -[QCocoaApplicationDelegate application:openFiles:] + 407
9   com.apple.AppKit               0x00007fff8dbe3eb5 __-[NSApplication(NSAppleEventHandling) _handleAEOpenDocumentsForURLs:]_block_invoke_1 + 1064
10  com.apple.AppKit               0x00007fff8d92bb4d __-[NSDocumentController(NSInternal) _autoreopenDocumentsWithCompletionHandler:]_block_invoke_2 + 111
11  com.apple.AppKit               0x00007fff8d92b7a2 -[NSDocumentController(NSInternal) _autoreopenDocumentsWithCompletionHandler:] + 725
12  com.apple.AppKit               0x00007fff8d95b027 -[NSPersistentUIManager finishedRestoringWindowsWithZOrder:registerAsReady:completionHandler:] + 6623
13  com.apple.AppKit               0x00007fff8e140b91 __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3 + 264
14  com.apple.AppKit               0x00007fff8e142624 __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_2 + 156
15  com.apple.AppKit               0x00007fff8db7d740 __-[NSApplication(NSPersistentUISupport) _restoreWindowWithRestoration:handler:]_block_invoke_1 + 601
16  com.apple.AppKit               0x00007fff8db6cdf3 -[NSApplication(NSPersistentUISupport) _restoreWindowWithRestoration:handler:] + 981
17  com.apple.AppKit               0x00007fff8d9582a9 -[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:] + 2119
18  com.apple.AppKit               0x00007fff8db6c7cb -[NSApplication(NSAppleEventHandling) _handleAEOpenDocumentsForURLs:] + 272
19  com.apple.AppKit               0x00007fff8d92ad86 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 307
20  com.apple.CoreFoundation       0x00007fff91ce6591 -[NSObject performSelector:withObject:withObject:] + 65
21  com.apple.Foundation           0x00007fff89a7b7eb __-[NSAppleEventManager setEventHandler:andSelector:forEventClass:andEventID:]_block_invoke_1 + 101
22  com.apple.Foundation           0x00007fff89a7a772 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 283
23  com.apple.Foundation           0x00007fff89a7a600 _NSAppleEventManagerGenericHandler + 105
24  com.apple.AE                   0x00007fff9501fc25 aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned int, unsigned char*) + 200
25  com.apple.AE                   0x00007fff9501fb03 _ZL25dispatchEventAndSendReplyPK6AEDescPS_ + 38
26  com.apple.AE                   0x00007fff9501f9f7 aeProcessAppleEvent + 250
27  com.apple.HIToolbox           0x00007fff8c22faf9 AEProcessAppleEvent + 102
28  com.apple.AppKit               0x00007fff8d9281a9 _DPSNextEvent + 1247
29  com.apple.AppKit               0x00007fff8d927861 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
30  com.apple.AppKit               0x00007fff8d92419d -[NSApplication run] + 470
31  QtGui                         0x0000000100241e21 QEventDispatcherMacPrivate::ensureNSAppInitialized() + 103
32  QtGui                         0x0000000100242d69 QEventDispatcherMacPrivate::currentModalSession() + 227
33  QtGui                         0x0000000100243141 QEventDispatcherMac::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 489
34  QtCore                         0x0000000100f19f08 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 394
35  QtGui                         0x00000001006da4c3 QDialog::exec() + 243
36  QtGui                         0x00000001006fc67e _ZL17showNewMessageBoxP7QWidgetN11QMessageBox4IconERK7QStringS5_6QFlagsINS1_14StandardButtonEES7_ + 318
37  QtGui                         0x00000001006fc773 QMessageBox::warning(QWidget*, QString const&, QString const&, QFlags<QMessageBox::StandardButton>, QMessageBox::StandardButton) + 39
38  com.kambala.MedianXLOfflineTools 0x000000010002b8dd QMessageBox::warning(QWidget*, QString const&, QString const&, QMessageBox::StandardButton, QMessageBox::StandardButton) + 93 (qmessagebox.h:260)
39  com.kambala.MedianXLOfflineTools 0x00000001000097d5 MedianXLOfflineTools::processSaveFile(QString const&) + 10277 (medianxlofflinetools.cpp:1457)
40  com.kambala.MedianXLOfflineTools 0x00000001000068ff MedianXLOfflineTools::loadFile(QString const&) + 591 (medianxlofflinetools.cpp:90)
41  com.kambala.MedianXLOfflineTools 0x0000000100003350 MedianXLOfflineTools::MedianXLOfflineTools(QString const&, QWidget*, QFlags<Qt::WindowType>) + 1168 (medianxlofflinetools.cpp:78)
42  com.kambala.MedianXLOfflineTools 0x0000000100002eb5 MedianXLOfflineTools::MedianXLOfflineTools(QString const&, QWidget*, QFlags<Qt::WindowType>) + 37 (medianxlofflinetools.cpp:81)
43  com.kambala.MedianXLOfflineTools 0x000000010009dd58 Application::Application(int&, char**) + 2200 (application.cpp:41)
44  com.kambala.MedianXLOfflineTools 0x000000010009d4b5 Application::Application(int&, char**) + 37 (application.cpp:43)
45  com.kambala.MedianXLOfflineTools 0x0000000100002dfe main + 46 (main.cpp:6)
46  com.kambala.MedianXLOfflineTools 0x0000000100002daa _start + 248
47  com.kambala.MedianXLOfflineTools 0x0000000100002cb1 start + 33
Пробовал закомментировать вызов isWindowModified(), но это не помогло - крашит буквально через пару строк, при чтении файла через readAll().

Собственно вопрос: как это предотвратить? Хотелось бы как-то дождаться какого-то события или момента времени, чтобы знать пришло ли это уведомление, и в зависимости от этого грузить последний файл или этот открытый. Или может есть какие-то другие способы? Вариант убрать уведомления не подходит, разве что если их можно как-то слегка отложить.
« Последнее редактирование: Март 19, 2012, 02:53 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #1 : Март 18, 2012, 20:42 »

Похоже вы вызываете методы по невалидному указателю.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« Ответ #2 : Март 18, 2012, 20:53 »

но ведь главное окно (объект типа MedianXLOfflineTools) не уничтожается само по себе? вызов его методов же проходит.

тут явно как-то виноват цикл событий QMessageBox'а, но что с этим можно сделать?
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« Ответ #3 : Март 19, 2012, 02:49 »

в общем, пока что остановился на грязном хаке через таймер, но готов выслушать решения получше.
Код
C++ (Qt)
// Application.h
class Application : public QApplication
{
   Q_OBJECT
 
public:
   explicit Application(int &argc, char **argv);
   virtual ~Application();
 
protected:
#ifdef Q_WS_MACX
   bool event(QEvent *ev);
#endif
 
private slots:
   void createAndShowMainWindow();
 
private:
   MainWindow *_mainWindow;
   QString _param;
#ifdef Q_WS_MACX
   QTimer *_showWindowMacTimer;
#endif
};
Код
C++ (Qt)
// Application.cpp
Application::Application(int &argc, char **argv) : QApplication(argc, argv), _mainWindow(0), _showWindowMacTimer(0)
{
   if (argc > 1)
       _param = argv[1];
#ifdef Q_WS_MACX
   if (_param.isEmpty())
   {
       _showWindowMacTimer = new QTimer;
       _showWindowMacTimer->setSingleShot(true);
       connect(_showWindowMacTimer, SIGNAL(timeout()), SLOT(createAndShowMainWindow()));
       _showWindowMacTimer->start(0);
   }
   else
#endif
       createAndShowMainWindow();
}
 
Application::~Application()
{
   delete _mainWindow;
}
 
void Application::createAndShowMainWindow()
{
   _mainWindow = new MainWindow(_param);
   _mainWindow->show();
 
   if (_showWindowMacTimer)
       delete _showWindowMacTimer;
}
 
#ifdef Q_WS_MACX
bool Application::event(QEvent *ev)
{
   if (ev->type() == QEvent::FileOpen)
   {
       _param = static_cast<QFileOpenEvent *>(ev)->file();
       if (!_mainWindow)
       {
           _showWindowMacTimer->stop();
           delete _showWindowMacTimer;
           _showWindowMacTimer = 0;
 
           createAndShowMainWindow();
       }
       else
           _mainWindow->loadFile(_param);
       return true;
   }
   return QApplication::event(ev);
}
#endif
« Последнее редактирование: Март 19, 2012, 02:52 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #4 : Март 19, 2012, 09:24 »

Может из QApplication::event() нельзя запускать другой эвентлуп? Можете проверить, например на мауспрессеили нажатии определенной кнопки?
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« Ответ #5 : Март 19, 2012, 17:32 »

если я правильно понял что надо сделать, то посылка sendEvent отрабатывает спокойно, а postEvent крашится с сообщением в консоль "error for object 0x7fff5fbfe4f0: pointer being freed was not allocated".
Код
C++ (Qt)
bool Application::event(QEvent *ev)
{
   if (ev->type() == QEvent::FileOpen)
   {
       QMouseEvent e(QEvent::MouseButtonPress, QPoint(50,50), Qt::LeftButton, 0, 0);
       (send|post)Event(_mainWindow, &e);
       _mainWindow->loadFile(static_cast<QFileOpenEvent *>(ev)->file());
       return true;
   }
   return QApplication::event(ev);
}
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #6 : Март 19, 2012, 18:55 »

нет, не то. просто проверить - можно ли в эвенте запускать новый эвентлуп
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« Ответ #7 : Март 19, 2012, 19:10 »

вставил вместо посылки события
Код
C++ (Qt)
QEventLoop loop;
loop.exec();
теперь файл попросту не открывается, но программа спокойно продолжает работать
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #8 : Март 20, 2012, 09:35 »

А мессаджбокс запустить?
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #9 : Март 20, 2012, 09:59 »

если я правильно понял что надо сделать, то посылка sendEvent отрабатывает спокойно, а postEvent крашится с сообщением в консоль "error for object 0x7fff5fbfe4f0: pointer being freed was not allocated".
Цитата: assistant
The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted. It is not safe to access the event after it has been posted.

Можно попробовать использовать не статический QMessageBox.
« Последнее редактирование: Март 20, 2012, 10:02 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4727



Просмотр профиля WWW
« Ответ #10 : Март 20, 2012, 18:32 »

А мессаджбокс запустить?
не крашит - пробовал как без родителя, так и с родителем-главным окном, при чем бокс появляется после появления главного окна, хотя вызывается перед loadFile(), но в этот момент в программе загружен последний использованный файл (так и должно быть, ведь цикл событий блокируется). если поставить бокс после, то тоже все ок, и он появляется после загрузки нового файла.
если я правильно понял что надо сделать, то посылка sendEvent отрабатывает спокойно, а postEvent крашится с сообщением в консоль "error for object 0x7fff5fbfe4f0: pointer being freed was not allocated".
Цитата: assistant
The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted. It is not safe to access the event after it has been posted.

Можно попробовать использовать не статический QMessageBox.
не помогло. еще я пробовал показать бокс через show вместо exec, но он просто не появлялся.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.212 секунд. Запросов: 22.