Windows, DLLs, C++ and pain...

BlitzMax Forums/Brucey's Modules/Windows, DLLs, C++ and pain...

Brucey(Posted 2011) [#1]
As it happens, Qt is the best cross-platform desktop GUI available (no, really... which is a shame considering all that other stuff of late), and I have a work-in-progress monster module to use it in BlitzMax.

But lately, whether it is a problem with the newer GCCs (possible) or with Qt 4.7.1 (less likely), I have started to see some issues on Windows with my not-so-overly-complex wrapper code.
Funnily enough, it all works fine on non-Windows, which is why I wonder about DLLs, C++ and MinGW...

I'm only posting here, because I don't really have anywhere else to write about it. It's not a Qt problem, it's not a C++ problem, it's not a BlitzMax problem... it's all of them together - which kind of limits any useful suggestions coming from forums of the above mentioned...


Here's a brief summary of how my code works (it does, really, and very well when it does!) We'll use an actual example because real cases are better than "what ifs" :

A class :
class QGraphicsBlurEffect
{
protected:
    void draw(QPainter * painter);
}

It's bigger than that, of course, but this is the function we want to implement on the Max side.
We can override the draw() function to implement our own functionality. The draw() function is called by Qt when it wants to draw it.
To allow this in BlitzMax, we have to subclass QGraphicsBlurEffect :
class MaxQGraphicsBlurEffect : public QGraphicsBlurEffect
{
public:
    void defaultDraw(QPainter * painter) {
        QGraphicsBlurEffect::draw(painter);
    }
protected:
    void draw(QPainter * painter) {
        _qt_qgraphicsblureffect_QGraphicsBlurEffect__draw(maxHandle, painter);
    }
}

... and have a matching BlitzMax Type :
Type QGraphicsBlurEffect

	Method draw(painter:QPainter)
		bmx_qt_qgraphicsblureffect_default_draw(qObjectPtr, painter.qObjectPtr)
	End Method
	
	Function _draw(obj:QGraphicsBlurEffect, painter:Byte Ptr)
		obj.draw(QPainter._create(painter))
	End Function
End Type


You'll notice from our subclass, that the real draw() function calls the _draw() function in our BlitzMax type.
This in turn calls the method draw() on our BlitzMax QGraphicsBlurEffect object instance.
If you haven't overridden the draw() method yourself, the default functionality is to call BACK down to call defaultDraw(), which calls draw() on the superclass.

In essence, by default, on a draw() call, you are calling QGraphicsBlurEffect::draw() (which is the standard calling convention for calling a function of the same name on the superclass).

Here's the summary :
c++    MaxQGraphicsBlurEffect::draw()
bmx          -> Function _draw()
bmx                -> Method draw()
c++                      -> MaxQGraphicsBlurEffect::defaultDraw()
c++                            -> QGraphicsBlurEffect::draw()


Well, it doesn't work on Windows now, for some reason. It crashes in the call to QGraphicsBlurEffect::draw() from defaultDraw()... :-(

However, if I change my code to this, it works as expected:
class MaxQGraphicsBlurEffect : public QGraphicsBlurEffect
{
public:
    void defaultDraw(QPainter * painter) {
        flag = 1;
    }
protected:
    void draw(QPainter * painter) {
        flag = 0
        _qt_qgraphicsblureffect_QGraphicsBlurEffect__draw(maxHandle, painter);
        if (flag) {
            QGraphicsBlurEffect::draw(painter);
        }
    }
}

Notice that we call superclass draw() from the original function (before we have gone to BlitzMax and back). This is not ideal, because you may not always want draw() to be called AFTER all of your own code...

Given this information, I can only assume something is getting out of sync between the call from the C++ to BlitzMax back down to the C++. Since I am using pointers, whose values are the same everywhere (I've checked), it's not a bad pointer problem.
I've even experimented with using reinterpret_cast<> on my MaxQGraphicsBlurEffect pointer for the call to defaultDraw(), but that hasn't helped either...

So, I don't know what is up with that.
As I say, it works on Linux and OS X as I expect it to...

...answers on a postcard to...

:-p

Last edited 2011


skidracer(Posted 2011) [#2]
No postcards at hand, but thought I'd make a few uninformed suggestions:

Disable GC in BlitzMax?

Using matching MingW 44_1 as distributed by Nokia?

Considered ditching MingW entirely in favor of VC++? I use to have a bmk variant that didn't seem to mind using the superior tool chain, although I suspect some of your more esoteric modules may complain...


Brucey(Posted 2011) [#3]
Thanks for the suggestions :-)

I might give that MinGW a try... although I always build the DLLs myself anyway - with a custom configuration - so I'm not sure if it would make too much difference... but you never can tell with these things.

The GC *shouldn't* be an issue... since I can guarantee that none of the involved objects are being cleansed during the callbacks.

It *was* working in a prior version of Qt (4.5 ish), and MinGW 3.x .... which is what makes it most disappointing.


As for VC++... yes, it has been considered... but the biggest problem here would be persuading people to migrate to it - unless it turned out to be a better over-all platform to work on, of course!


skidracer(Posted 2011) [#4]
but the biggest problem here would be persuading people to migrate to it - unless it turned out to be a better over-all platform to work on, of course!


I was thinking if MinGW continues to bungle it's distribution system and ignore it's legacy install base it may force the issue.

Maybe a win32 flavored LLVM will arrive in near future to rescue us.

I think for future of BlitzMax, a return to the mod server concept so users don't have to faff with toolchains, module rebuilds and hair pulling could be a consideration also.


markcw(Posted 2011) [#5]
Could it be a bug with Bmx? Or is it MinGW? Or is it even Qt? I am not much help really.