views:

287

answers:

1

I have a Windows/Linux Qt 4.3 application that uses drag and drop in a QTreeView. I have two very similar applications which use the same set of Qt libraries. Drag and drop works in both on Linux but in only in one on Windows.

In the application that does not work the QDrag object gets deleted as soon as the mouse is moved. It is deleted by a DeferredDelete event from the event queue which is still processed in Qt during a drag. I do not know how to see what is causing the QDrag object to get deleted prematurely.

I can not figure out a good way to debug this problem. I have compared the source and cannot find anything obvious. I have tried using the code from one of the applications in the other application.

Any suggestions?

Update:

The reason the QDrag operation failed is because COM was not initialized successfully so the call to DoDragDrop in QDrag::exec returned immediately. QApplication tried to initialize COM by calling OleInitialize in qt_init but it failed with the error "Cannot change thread mode after it is set".

The interesting thing is that this happens even when OleInitialize is the first thing done in main so the thread mode is getting set initially by some external dependency. One of the differences between the applications that work on Windows is that the one that fails also contains .NET code so maybe that is the problem.

Solved:

This problem is a COM/CLR interop issue. The CLR sets the apartment state to MTA when it initializes and then when Qt attempts to initialize COM it fails. This problem and an old solution are discussed by Adam Nathan in Gotcha with STAThreadAttribute and Managed C++. In Visual Studio 2005 you can set the /CLRTHREADATTRIBUTE:STA compiler option in Configuration Properties > Linker > Advanced to set the threading attribute to STA without needing to create a new entry point.

+1  A: 

I have no idea what can cause this, but I would try to find out by subclassing QDrag, overwrite deleteLater() (well, reimplement it, but as it's a slot, it will get called anyway), use this instead of a QDrag and put a breakpoint in deleteLater().