Qt: Adding native OS Specific code to project - c++

My project is a Qt application written in C++, running on Windows, OS X and Linux. There is a certain area Qt doesn't cover in its abstraction: Iterating other application windows active on the desktop, and returning their names, their 'handles' and icons.
I have OS specific code to do just that.
Pure Win32/C++ on windows
Objective-C on OS X
and some X11 c++ code for linux
I'd like to build my own abstraction that would utilize those OS Specific native snippets to provide it the runtime data it needs.
So, I'd have to have objective-C code build and run with my OS X build
Win32/c++ with windows
and similar with Linux
Let's focus on Mac, just for this example. How do I combine an objective C class into my Qt C++ project? how do I call it from C++? Are there any samples where I can see how it's done?
Ideally I would like to have the OS specific code in the project, and not build separate shared libraries to be linked in, although this is an option if nothing else can be done.

I suppose I would create shared libraries in this situation. Anyway, what I'm about to suggest is an idea, but should work.
By using qmake capabilities, I would create a pro file with different configurations for each platforms, where each configuration (CONFIG variable) includes different sources (this is if you don't want to use simple ifdef's. What I commonly do is create a common header, and different implementations for each platform in a different cpp files. For instance:
/* platformaspecific.h */
class PlatformSpecific : public QObject
{
PlatformSpecific(QObject* parent = 0);
QList<void*> getHandleForWindows(...);
void doSomethingPlatformIndependent();
...
};
/* platformspecific_x11.cpp */
PlatformSpecific::PlatformSpecific(QObject* parent) : QObject(parent)
{
...
}
PlatformSpecific::getHandleForWindows(...)
{
...
}
...
/* platformspecific_win.cpp */
PlatformSpecific::PlatformSpecific(QObject* parent) : QObject(parent)
{
...
}
QList<void*> PlatformSpecific::getHandleForWindows(...)
{
...
}
/* platformspecific_common.cpp (if needed) */
void PlatformSpecific::doSomethingPlatformIndependent()
...
and so on...
Then, in your .pro file, you use different scopes and include the source files according to their related CONFIG.
CONFIG += X11
X11 {
SOURCES += platformspecific_x11.cpp
}
else:WIN {
SOURCES += platformspecific_win.cpp
}
...
SOURCES += platformspecific_common.cpp
After this, for the part including Objective-C you'll have to use Objective-C++. You can mix C++ and Objective-C quite easily with Objective-C++, only some things are not allowed, like extending C++ classes with Objective-C and so on... You can find whatever you need to program using Objective-C++ in the Apple Dev Center. I don't know how good is programming in Objective-C++ using Qt Creator, but anyway you can always create a Xcode project from the .pro file using qmake: read this http://doc.qt.io/archives/qt-4.7/qtmac-as-native.html#development-tools.
By using this approach, or something similar it should be quite comfortable to work.

I would recommend making them static libraries and linking them in. It makes the code simple and direct. It adds the complexity to the build, but generally speaking, it is all or nothing. Once you get it working, there aren't any gotchas.
Things like preprocessor defines work, but when they break it isn't always obvious to the developer why.

Related

Use NetCDF4-C in Unity

this is my first time posting (after lurking for years).
A project I will be tackling is to use NetCDF4 (.nc) files in Unity on Windows. I will be using Unity 5.4.0f3 and Windows 10, and I have developed in Unity before and am familiar with C# and JavaScript, but NetCDF only has C, Java, and Fortran APIs, although there are wrappers in Python, C++, and others (source: https://www.unidata.ucar.edu/publications/factsheets/current/factsheet_netcdf.pdf).
So my specific question is how do I call NetCDF4-C functions (nc_get_vara_float(), nc_open, etc) in C# for use in Unity?
What I've tried so far:
To start, I googled specifically for NetCDF4-C + Unity tutorials/attempts, but did not find anything, so instead I have been looking into the compatibility of calling C functions from C#. I am currently working on a project on Linux with NetCDF4-C and written custom wrapper functions for the netcdf.h functions, so I was hoping I could reuse my code there.
I attempted to follow this SO post (Is it possible to call a C function from C#.Net) but get an error in Unity when trying to Play: "DllNotFoundException: test.so" (my file was named "test.c"). From the comments, it seems Linux uses .so files but Windows uses .dll, and I was not sure how to generate a .dll of a C file.
I looked up another post on that (How to write a DLL file in C?) and downloaded Visual Studio to follow along. While VS was downloading, I looked up how to use GCC to compile (Creating a DLL in GCC or Cygwin?), and used the Bash subsystem ("Bash on Ubuntu on Windows" terminal) but got a handful of errors that indicated the code from the previous link (2nd SO link in this post) were for C++, so I stopped working with GCC.
Once VS finished installing, I went back to trying to use VS to create the .dll, and attempted to combine the solutions from both SO posts (1 and 2) so that I would be able to use the .dll file containing C code in Unity, but to no avail: I get the same error but just with a different extension (and different name on purpose): "DllNotFoundException: Win32Project1.dll".
The code I have is as follows:
test.cs (used in Unity and attaches to a Component):
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class test : MonoBehaviour {
[DllImport("Win32Project1.dll", EntryPoint="DisplayHelloFromMyDLL")]
public static extern void DisplayHelloFromMyDLL ();
// Use this for initialization
void Start () {
DisplayHelloFromMyDLL();
}
// Update is called once per frame
void Update () {
}
}
Win32Project1.dll (created and built in Visual Studio):
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DisplayHelloFromMyDLL()
{
printf("Hello DLL.\n");
}
}

Accessing static members of a class from dll

I have application written in C++ that uses SWIG for python integration.
Now under linux/osx when i build swig wrapper it creates so file that is used from application like this.
Py_Initialize();
PyRun_SimpleString("import MoBridge");
PyRun_SimpleString("a = MoBridge.MoBridge()");
PyRun_SimpleString("a.CreateQuadMesh()");
Py_Finalize();
What this does is it imports wrapper MoBridge, then it calls trough wrapper C++ function CreateQuadMesh(). Wrapper roughly looks roughly like this
h file:
#include "MoEngine.h"
class MoBridge
{
public:
MoBridge();
~MoBridge();
void CreateQuadMesh();
};
cpp file:
#include "mobridge.h"
void MoBridge::CreateQuadMesh()
{
MoEngine::CreateMesh();
}
The wrapper calls MoEngine static function and it in turn does what it does.
Now this works great under Linux/osx if I understood it correctly because the way so file is linked.
But under windows I had to create DLL and as far as I found DLL files are loaded differently so they live in different memory from the rest of the application and hence cannot see applications other static methods.
I know that I can use dllexport to expose methods from dll to the rest of the application. But in this case I'm looking on how to allow dll to access rest of the applications static functions in applications memory.
I would appreciate any point in the right direction.
If anyone gets stuck with this I have found solution that will resolve this in both linux, osx and windows.
using shared object *.so will of course work with linux/osx but luckily there is even easier solution to use with SWIG that is really not documented in SWIG but it's documented in python documentation (thank you python!)
For this to work you don't need to create dll or so file from your wrapper but after swig creates your *_wrap.cxx file you should include it in your project and before calling Py_Initialize() you import your module like this.
PyImport_AppendInittab("_MoBridge", PyInit__MoBridge);
Then you can use as previously mentioned:
Py_Initialize();
PyRun_SimpleString("import MoBridge");
PyRun_SimpleString("a = MoBridge.MoBridge()");
PyRun_SimpleString("a.CreateQuadMesh()");
Py_Finalize();
And basically since you have your *_wrap.cxx in your project and python is essentially living within your application since you initialised it you have exactly same behaviour like if you have used so in linux/osx except this work on all three platforms.
Cheers!

Qt Signals and Slots break when converting Visual C++ project to boost build makefile project

I created a Visual C++ Project using MSVS and I just made another project in MSVS so that the same code can be built using boost build. I can currently build my project using a Visual C++ project as well as a Makefile project that uses boost build.
There is a difference between the two builds though concerning QT Signals and Slots.For the following code,when I call MyThread::Start() the onTimeout() slot is called when the project is built in visual studio, but not called when built using boost build.
class MyThread: public QObject{
Q_OBJECT
public:
bool start();
public Q_SLOTS:
void onTimeout();
private:
QThread m_thread;
QTimer m_timer;
};
void MyThread::start()
{
m_timer.start(1000);
m_thread.setObjectName(QString("GigeControl"));
m_thread.start();
m_timer.moveToThread(&m_thread);
}
void MyThread::onTimeout()
{
//Do Stuff
}
I am really having a hard time trying to figure out the differences between the two
builds,especially since I need those signals and slots to work.
One major difference that I have noticed so far is that the Visual C++ project is built using /Zp1 so all structures are 1 byte alligned. This is not done in the boost project as I don't know how to. I've seen people on the internet mentioning that structure allignments (especially using #pragma pack can cause problems with QT).
If anyone has some experience they might be able to share it would be greatly appreciated.
It looks like the problem was in fact the structure packing. I am writing code for a couple of code bases that are being merged and there coincidentally happens to be some packing conflicts.
To fix the packing for building with boost-build all I had to to was add this to the lib being generated in the Jamfile:
lib foo
:
...
:
...
<target-os>linux:<cxxflags>-fpack-struct=1
<target-os>windows:<cxxflags>-Zp1
;
This worked for me so hopefully it will help someone else out if they get stuck here too

How to run a simple cpp file that requires QT?

I have QT 5.1.1 installed on my machine, but I'm having some troubles using it. I'm trying to run the following simple program that requires QT:
//Playing Video
#include "cv.h"
#include "opencv2\objdetect\objdetect.hpp"
#include "opencv2\core\core.hpp"
#include "opencv2\highgui\highgui.hpp"
#include "opencv2\features2d\features2d.hpp"
#include "opencv2\calib3d\calib3d.hpp"
#include "opencv2\nonfree\nonfree.hpp"
#include "highgui.h"
#include <openbr\openbr_plugin.h>
using namespace cv;
static void printTemplate(const br::Template &t)
{
const QPoint firstEye = t.file.get<QPoint>("Affine_0");
const QPoint secondEye = t.file.get<QPoint>("Affine_1");
printf("%s eyes: (%d, %d) (%d, %d)\n", qPrintable(t.file.fileName()), firstEye.x(), firstEye.y(), secondEye.x(), secondEye.y());
}
int main(int argc, char *argv[])
{
br::Context::initialize(argc, argv);
// Retrieve classes for enrolling and comparing templates using the FaceRecognition algorithm
QSharedPointer<br::Transform> transform = br::Transform::fromAlgorithm("FaceRecognition");
QSharedPointer<br::Distance> distance = br::Distance::fromAlgorithm("FaceRecognition");
// Initialize templates
br::Template queryA("../data/MEDS/img/S354-01-t10_01.jpg");
br::Template queryB("../data/MEDS/img/S382-08-t10_01.jpg");
br::Template target("../data/MEDS/img/S354-02-t10_01.jpg");
// Enroll templates
queryA >> *transform;
queryB >> *transform;
target >> *transform;
printTemplate(queryA);
printTemplate(queryB);
printTemplate(target);
// Compare templates
float comparisonA = distance->compare(target, queryA);
float comparisonB = distance->compare(target, queryB);
// Scores range from 0 to 1 and represent match probability
printf("Genuine match score: %.3f\n", comparisonA);
printf("Impostor match score: %.3f\n", comparisonB);
br::Context::finalize();
return 0;
}
It also requires OpenCV 2.4.6.1 and OpenBR, but that's not the problem.
All the definitions (variables and functions) in the above code that are related to QT are undefined. I've tried to find the relevant h files in QT folder and to include them, but that did not succeed since I couldn't fine qtcore.h (but a different file named qtcore with lot's of includes that I don't now how to use). I've tried to add QT "include" directory under "additional include directories" in the project properties but that didn't work either. I've also tried to add QT "lib" folder under "additional library directories" but that also did not work.
Basically, I tried everything I could think of. Can someone please explain how to I use those QT definitions? I'm really stuck and I could use any help given.
Thanks,
Gil.
(Optional) Update to Qt 5.2.
Start Qt Creator.
Create a new Qt Widgets Application project. You can give the class/files random names, it doesn't matter. Uncheck the "generate form" option, as you don't need any forms.
Remove all the files other than main.cpp from the project. You do this by right-clicking on them in the project tree on the left and choosing Remove File.
Copy-paste your code into main cpp. Make sure you completely replace main.cpp's contents, the default contents shouldn't be there anymore.
Add the opencv library to the project. Right-click on the project's root, select "Add Library", and go from there.
Re-run qmake by right-clicking on the project root and selecting "Run qmake".
Build and run the project by pressing Ctrl-R (Cmd-R on mac).
Qt uses a (non-standard) custom toolchain that has to run before the Qt-dependent code can be compiled. I've never tried using Qt outside of QtCreator, but if you really need Qt I'd suggest you use the QtCreator IDE; if you're not using it already of course. It's a very decent IDE, even for non-Qt projects.
Also, if you haven't done so already, make sure the Qt SDK is installed; the headers alone are not enough. QtCreator by itself is also not enough, you'll need the SDK. If you don't feel like doing so, my suggestion would be to look at Poco. It's not a 1:1 replacement for Qt, but a very mature framework nevertheless.

Windows/opengl glext.h build issue

So I'm trying to bring a c++ project using Qt and OpenGL written and compiled on a Linux machine over to my Windows 7 machine at home, but I'm running into some difficulty. First I learned that some gl things (like GL_TEXTURE0) were no longer defined because gl.h doesn't define them for windows. Also, the glext.h that I have does not define some functions like glActiveTexture. Both of these issues I found could be solved by bringing in a newer glext.h.
My most immediate issue seems to be that I'm not bringing it in correctly. If I do:
#define GL_GLEXT_LEGACY //should prevent old glext.h from being included
#define GL_GLEXT_PROTOTYPES //should make glActiveTexture be defined
#include <qgl.h>
#include "glext.h" //local up-to-date glext.h
#include <QGLShaderProgram>
then make tells me that I have undefined references to glActiveTexture. If I include QGLShaderProgram before glext.h, then I still have that problem, but make also warns me that I am redefining quite a few things that are defined in both QGLShaderProgram and glext, so I know the latter file is being included. Any help would really be appreciated.
You are on a right path, but like Nick Meyer wrote, you need to get pointers to the functions at runtime.
There is a nice and clean example already in Qt installation directory, at least since 4.6. Check "Boxes" from "demos"-directory. There is glextensions.h/cpp that takes care of those required functions in Qt-way, using Qt's QGLContext etc.
If you're lazy like me, just hop over to
http://glew.sourceforge.net
and use that, no need to fiddle around with different header files and manually retrieving function pointers. It's as simple as
/* in every source file using OpenGL */
#include <GL/glew.h>
and
/* for each OpenGL context */
if( createGLContext(...) == SUCCESSFULL )
glewInit()
If you're using Qt you should probably use qmake - and just add
QT += opengl
to your qmake project file.