My .DLL cannot find sql drivers
-
Hi all,
Today I spent some time to make a dll that basically wraps around qt's database capabilities. I built the dll and made an executable in Qt that calls the dll. I can run this executable and it runs fine.
The problem is when I call the DLL from LabVIEW. It is giving me an error "Driver not loaded". This is the typical error that i see a lot of people have. However I can run my executable calling the dll that I wrote in c++ on the same computer. When I use the windeploy tool it automatically puts the sqldrivers into the folder, I also have Qtcore and qtsql dlls in the directory as well. The .dll calls are working because I can run other components of my library that is how I am getting the driver not loaded error back into LV. In addition when I run the QSqlDatabase::drivers() it returns nothing when I run in labview but the executable calling the same code returns 7 and lists off the usual drivers.
Hopefully someone can give me a hand with this because the LV Database connectivity toolkit sucks and labview NXG doesn't support the toolkit either.
Thanks,
-Shawn -
Okay, looks to be more complicated than I was expecting. I am studying the main.cpp now with the startwidgetengine and run.
There is a lot more to it than I thought xD.
Thanks.
@MrShawn said in My .DLL cannot find sql drivers:
Okay, looks to be more complicated than I was expecting. I am studying the main.cpp now with the startwidgetengine and run.
There is a lot more to it than I thought xD.
So much boilerplate code is needed because:
- Most of Qt's classes are not thread-safe, so an object instance can only be accessed from one thread.
- Furthermore, GUI classes are not even reentrant; they can only be accessed from the thread which instantiates
QGuiApplication
/QApplication
.
- Furthermore, GUI classes are not even reentrant; they can only be accessed from the thread which instantiates
- LabVIEW is implicitly multi-threaded. It automatically distributes your code among the available threads. This means each time LabVIEW calls your DLL, it could use a different thread from the last call.
QCoreApplication::exec()
blocks the thread until you quit.- (minor reason) I use a code generator to produce most of that library. The generator is optimized to simplify my life; it is currently not optimized to produce the simplest code.
The main things you need to do to wrap your own Qt-based DLL to be called by LabVIEW are:
- Spawn a long-lived
std::thread
, dedicated to Qt's classes. - In that thread, instantiate a
QCoreApplication
(or a subclass) and exec() the event loop. - For all functions called by LabVIEW, use
QMetaObject::invokeMethod()
to ensure that your Qt objects are accessed from the Qt thread.
I have also used this approach to integrate other 3rd-party, non-Qt, C/C++ libraries into LabVIEW projects.
If you find something unclear, just ask and I'll do my best to answer.
P.S. The LQWidgets library is long overdue for a cleanup and simplification, to take advantage of new features from Qt 5.10 (mainly the ability for
QMetaObject::invokeMethod()
to accept lambdas) - Most of Qt's classes are not thread-safe, so an object instance can only be accessed from one thread.
-
@JKSH
So I am not using any GUI components.Looking at your code and trying to see how it works I am aiming to mimic your startwidgetengine and run.
For now I have a static method that calls a startup function similar to your run() by doing the same std::thread approach. I am not sure if it is valid but to ensure my object is in that thread I create the object in my startup function. I return a pointer back to the object. With the pointer I basically call static methods which take the pointer as an int and then cast it appropriately and use the object.When I test in qt both from IDE run and with compiled executable outside qt creator it works. I do get a warning saying QApplication was not created in main() thread. However it does find my drivers and seems to work. In LV still nothing sadly regarding finding sql drivers :(.
I am trying to run your code to provide some insight. I am trying to compile the .dll but I need help with one part. It has something to do with this in the readme. "^ MinGW 4.9.2 is tested and it works, but it is not supported by National Instruments. To use MinGW, you need to modify the external header, \cintools\platdefines.h, to make it accept the GCC compiler on Windows."
I am getting an error "We do not know the Compiler". I am sure you can guess which compiler I am using :). What do I add to allow compatibility to MinGW 5.3.0.-Shawn
-
@JKSH
So I am not using any GUI components.Looking at your code and trying to see how it works I am aiming to mimic your startwidgetengine and run.
For now I have a static method that calls a startup function similar to your run() by doing the same std::thread approach. I am not sure if it is valid but to ensure my object is in that thread I create the object in my startup function. I return a pointer back to the object. With the pointer I basically call static methods which take the pointer as an int and then cast it appropriately and use the object.When I test in qt both from IDE run and with compiled executable outside qt creator it works. I do get a warning saying QApplication was not created in main() thread. However it does find my drivers and seems to work. In LV still nothing sadly regarding finding sql drivers :(.
I am trying to run your code to provide some insight. I am trying to compile the .dll but I need help with one part. It has something to do with this in the readme. "^ MinGW 4.9.2 is tested and it works, but it is not supported by National Instruments. To use MinGW, you need to modify the external header, \cintools\platdefines.h, to make it accept the GCC compiler on Windows."
I am getting an error "We do not know the Compiler". I am sure you can guess which compiler I am using :). What do I add to allow compatibility to MinGW 5.3.0.-Shawn
@MrShawn said in My .DLL cannot find sql drivers:
For now I have a static method that calls a startup function similar to your run() by doing the same std::thread approach. I am not sure if it is valid but to ensure my object is in that thread I create the object in my startup function. I return a pointer back to the object. With the pointer I basically call static methods which take the pointer as an int and then cast it appropriately and use the object.
Sounds good.
When I test in qt both from IDE run and with compiled executable outside qt creator it works.... In LV still nothing sadly regarding finding sql drivers :(.
Since you can run the compiled executable outside Qt Creator, I guess you have deployed all dependencies correctly.
Did you call
QCoreApplication::addLibraryPath()
? Pass the root folder which contains your main DLL.I am getting an error "We do not know the Compiler". I am sure you can guess which compiler I am using :). What do I add to allow compatibility to MinGW 5.3.0.
Open platdefines.h and search for the string, "We don't know the compiler." Insert these 2 lines above the final
#else
:#elif __GNUC__ #define Compiler kGCC
(These lines are copied+pasted from the Linux section of platdefines.h. MinGW is GCC, after all!)
I do get a warning saying QApplication was not created in main() thread.
Hmm, I don't think you should get this message if you're running from an executable outside of the IDE. Are you using any Qt classes in your main thread?
In the LabVIEW IDE, the first run shouldn't produce this message. However, if you stop the Qt thread and re-run your DLL again without restarting LabVIEW, you will see this message because the first run initialized some persistent global resources. This message is mostly harmless but some things stop working at this point (e.g.
QWinThumbnailToolButton
).This is an annoyance during development, but it shouldn't affect your released application.
-
HOLY SH*T IT WORKED!
@JKSH you are the man!!!
I did have that but I put in the direct .dll filename/path once i just sent it the folder it worked!
7 drivers, all found!!!