PDA

View Full Version : Question about classes in Qt



waynew
3rd November 2010, 23:40
I am admittedly a newbie to both Qt and C++, therefore this question.
(Almost all of my posts are asking questions and many thanks to those who have taught me)

I am stumped in trying to use a 3rd party library written in C++.
If I build a dll from their source, using Mingw, it won't load into my Qt application.
Although a test Windows dll will.

So I tried using the .a library I built from their source as a static library with my application (my application compiles ok with this).

Then comes the question. It seems to me, looking at the Qt examples, that Qt expects the header file to define a class for the source file (and that is the way I have written my application). But this 3rd party application is written in a manor where the header doesn't always define the classes (that I need) in the source file (but they are defined there). So I don't know how to create an object for the class I need to call functions from the 3rd party library.
How can one handle this in Qt?

Can someone please explain this to me or point me to a reference so I can figure it out. My Qt and C++ books don't seem to help much here.

ChrisW67
4th November 2010, 07:09
I am stumped in trying to use a 3rd party library written in C++. If I build a dll from their source, using Mingw, it won't load into my Qt application. Although a test Windows dll will.

This sounds like a purely run-time linking issue. The DLL has to be in the same directory as the compiled executable or in the system path/Windows directories if its not a Qt Plugin. If it is a Qt plugin then it may need to be in a subdirectory relative to the executable (by default anyway).


So I tried using the .a library I built from their source as a static library with my application (my application compiles ok with this).
Good, so this is not a mismatched compiler issue.



Then comes the question. It seems to me, looking at the Qt examples, that Qt expects the header file to define a class for the source file (and that is the way I have written my application). But this 3rd party application is written in a manor where the header doesn't always define the classes (that I need) in the source file (but they are defined there). So I don't know how to create an object for the class I need to call functions from the 3rd party library.
How can one handle this in Qt?


The header file is needed by other code so that is knows what data structures exist in the library in order to compile code that uses them. The library source file can also define classes and other data structure for use internally. These are not generally accessible from outside the library. You said that your program compiles, so the library headers you have included in your sources are adequate.

waynew
4th November 2010, 11:57
Thanks Chris - that clears up some things.
I can see that the functions in the library that I need to use are declared DLLEXPORT
So it seems the only question now is how to access those functions from my Qt application - that is, what would the syntax look like?

wysota
4th November 2010, 12:25
So it seems the only question now is how to access those functions from my Qt application - that is, what would the syntax look like?
Just call them as any other functions/methods.

waynew
4th November 2010, 22:27
I'm a little worried now. Trying to access one of the functions and I get an error that it hasn't been defined.
So to test if the library is really linking, I checked the file size of the release exe, then commented out the library lines in the .pro file, ran qmake, then rebuilt. The exe file is still the same size. Seems to me if the static library was being included, the size of the exe should increase.
Is there any way to check using the application code if the library is actually included other than trying to call a function in it?

And if qmake runs with no error and the build also, with the library lines in the .pro, why would the library not be included?
Here are the library lines:


INCLUDEPATH += C:\cpp\qt_projects\hrlogger_development\debug\tqsl lib
LIBS += -L"C:\cpp\qt_projects\hrlogger_development\debug\tqsl lib"
LIBS += -ltqsllib

I am using the static library qserialdevice in the same manner with no problems at all.
Only difference with qserialdevice is that I create an object for the class with the functions in it that I need.

SixDegrees
4th November 2010, 22:48
Definition occurs in the header file. You're using the same path for both the include statement - which pulls in the header files - and for the library location. This would be an unusual configuration; headers are normally located in their own directory.

Missing header files generate undefined symbol errors; missing libraries generate undefined references (to the functions that can't be found).

Look around in the directory your external library is installed in, and see if you can find a .h file; put that directory in your include path, and include that file in your own source code.

waynew
4th November 2010, 23:04
Thanks Six, yeah, I did all of that. I built the library under my mingw/msys/1.0/home/user directory then made the tqsllib directory under my application for simplicity and copied the .h files I needed and the library file there.

Seems to me the library is not loading/linking when I do the build. I get no errors, but the exe is not getting any bigger than building without the library and I think it should. Then when I add code to call a function in the library I get the undefined reference error.

wysota
4th November 2010, 23:25
What is the exact error you are getting?

waynew
5th November 2010, 00:54
Here's the error message Wysota:

C:/CPP/QT_Projects/HRLogger_Development/lotwupload.cpp:12: error: 'tqsl_getStationLocation' was not declared in this scope

That function is defined in the library as DLLEXPORT int tqsl_getStationLocation(tQSL_Location *locp, const char *name)

wysota
5th November 2010, 01:00
This is not a linker error but a compiler error. You are missing a prototype of the function. Are you including the proper header file?

waynew
5th November 2010, 12:04
Ooops, I forgot to uncomment the header includes when I added the library back in.

Now the compiler is complaining because I am not calling the function correctly, which is
DLLEXPORT int
tqsl_getStationLocation(tQSL_Location *locp, const char *name)

So, this becomes a C++ problem as my app definitely seems to see the library.
Thank you for your assistance gentlemen and I'm back to the C++ books to see how to make this work.
I truly appreciate your help.

tbscope
5th November 2010, 12:23
What error?

waynew
5th November 2010, 23:24
Well tbscope, I'm not getting an error on the function call now, but on the things that precede it.

Yeah, I know, this is basic C++ stuff, but I'm a 66 year old dog trying to learn new tricks and my native language is pl/sql.

Here is the code from the library:


//from the header
typedef void * tQSL_Location;
//from the source
class TQSL_LOCATION {
public:
TQSL_LOCATION() : sentinel(0x5445), page(0), cansave(false), sign_clean(false) {}
~TQSL_LOCATION() { sentinel = 0; }
int sentinel;
int page;
bool cansave;
std::string name;
TQSL_LOCATION_PAGELIST pagelist;
std::vector<TQSL_NAME> names;
std::string signdata;
bool sign_clean;
std::string tSTATION;
std::string tCONTACT;
std::string sigspec;
};

DLLEXPORT int
tqsl_getStationLocation(tQSL_Location *locp, const char *name)

So stumbling around in my usual way, in my application, I put in my LotwUpload class:


class TQSL_LOCATION;

LotwUpload::LotwUpload(QWidget *parent) :
QDialog(parent),
ui(new Ui::LotwUpload)
{
ui->setupUi(this);

TQSL_LOCATION tqslLocation = new TQSL_LOCATION();
tqslLocation = "K4ELO - K4ELO Farm";
int loc = tqsl_getStationLocation(tqslLocation, "my_name");
}

And the compiler errors are:
C:/CPP/QT_Projects/HRLogger_Development/lotwupload.cpp:14: error: variable 'TQSL_LOCATION tqslLocation' has initializer but incomplete type

C:/CPP/QT_Projects/HRLogger_Development/lotwupload.cpp:14: error: invalid use of incomplete type 'struct TQSL_LOCATION'

C:/CPP/QT_Projects/HRLogger_Development/lotwupload.cpp:6: error: forward declaration of 'struct TQSL_LOCATION'

So, unless someone is kind enough to explain to me what I am doing wrong, I'll just keep researching and stumbling until I get it to work :)

wysota
5th November 2010, 23:28
You are missing an include of the header file containing the definition of the TQSL_LOCATION class. Furthermore line #8 of the last snippet of code should probably read:

TQSL_LOCATION *tqslLocation = new TQSL_LOCATION;

waynew
6th November 2010, 00:07
Well Wysota, that's part of the problem, the class is only defined in the source, not the header. Why do people write code like this?
There must be a reason I don't understand, but that's just my lack of knowledge.
But your code correction is right, of course. I'm getting sloppy in my old age. Maybe too old to learn C++. But I'm still trying :)
So, I changed the code as you rightly suggested, and I am still getting the same errors.

wysota
6th November 2010, 08:48
Well Wysota, that's part of the problem, the class is only defined in the source, not the header. Why do people write code like this?
There must be a reason I don't understand, but that's just my lack of knowledge.
Maybe the class was never meant to be used by external developers? You can always move the definition to the header file if that doesn't break someone else's code.

waynew
6th November 2010, 13:19
I think I'm almost there (hopefully).
Again, here is the library function I need to call:


DLLEXPORT int
tqsl_getStationLocation(tQSL_Location *locp, const char *name)
// and in the header for the library:
typedef void * tQSL_Location;

So now I have in my code:


QString location = "my_location";
QString name = "my_name";
int loc = tqsl_getStationLocation(&location, &name);
qDebug() << "loc returns " << loc;

And the compiler error is:
C:/CPP/QT_Projects/HRLogger_Development/lotwupload.cpp:18: error: cannot convert 'QString*' to 'void**' for argument '1' to 'int tqsl_getStationLocation(void**, const char*)'
So what am I doing wrong?

wysota
6th November 2010, 15:34
You are passing a string where the function requires a pointer to the TQSL_Location structure (probably). With an ugly C cast, if I might add.

waynew
12th November 2010, 23:08
Thanks Wysota - I can see that now. :)
Like someone said, inexperience can be cured, but stupid is forever. I'm hoping to be in the first category.

Got sidetracked by other issues. Back to the problem I haven't solved yet.
Now the code looks like this:


tQSL_Location location;
QString locName = "K4ELO Farm";
char *myLoc = locName.toUtf8().data();
int loc = tqsl_getStationLocation(&location, myLoc);


And the compiler error is:
C:\CPP\QT_Projects\HRLogger_Development/lotwupload.cpp:18: undefined reference to `_imp__tqsl_getStationLocation@8'

So, is it really not seeing the library then?