Название: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: kambala от Март 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(). Собственно вопрос: как это предотвратить? Хотелось бы как-то дождаться какого-то события или момента времени, чтобы знать пришло ли это уведомление, и в зависимости от этого грузить последний файл или этот открытый. Или может есть какие-то другие способы? Вариант убрать уведомления не подходит, разве что если их можно как-то слегка отложить.
Название: Re: программа падает, если запускатеся при открытии файла
Отправлено: Авварон от Март 18, 2012, 20:42
Похоже вы вызываете методы по невалидному указателю.
Название: Re: программа падает, если запускатеся при открытии файла
Отправлено: kambala от Март 18, 2012, 20:53
но ведь главное окно (объект типа MedianXLOfflineTools) не уничтожается само по себе? вызов его методов же проходит.
тут явно как-то виноват цикл событий QMessageBox'а, но что с этим можно сделать?
Название: Re: программа падает, если запускается при открытии файла
Отправлено: kambala от Март 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
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: Авварон от Март 19, 2012, 09:24
Может из QApplication::event() нельзя запускать другой эвентлуп? Можете проверить, например на мауспрессеили нажатии определенной кнопки?
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: kambala от Март 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); }
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: Авварон от Март 19, 2012, 18:55
нет, не то. просто проверить - можно ли в эвенте запускать новый эвентлуп
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: kambala от Март 19, 2012, 19:10
вставил вместо посылки события C++ (Qt) QEventLoop loop; loop.exec();
теперь файл попросту не открывается, но программа спокойно продолжает работать
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: Авварон от Март 20, 2012, 09:35
А мессаджбокс запустить?
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: GreatSnake от Март 20, 2012, 09:59
если я правильно понял что надо сделать, то посылка sendEvent отрабатывает спокойно, а postEvent крашится с сообщением в консоль "error for object 0x7fff5fbfe4f0: pointer being freed was not allocated".
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.
Название: Re: [РЕШЕНО ЧЕРЕЗ ХАК] программа падает, если запускается при открытии файла
Отправлено: kambala от Март 20, 2012, 18:32
А мессаджбокс запустить?
не крашит - пробовал как без родителя, так и с родителем-главным окном, при чем бокс появляется после появления главного окна, хотя вызывается перед loadFile(), но в этот момент в программе загружен последний использованный файл (так и должно быть, ведь цикл событий блокируется). если поставить бокс после, то тоже все ок, и он появляется после загрузки нового файла. если я правильно понял что надо сделать, то посылка sendEvent отрабатывает спокойно, а postEvent крашится с сообщением в консоль "error for object 0x7fff5fbfe4f0: pointer being freed was not allocated".
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, но он просто не появлялся.
|