ok i have main.cpp which loads functions from a dll
have another second.cpp
how do i use functions from main.cpp in second.cpp
or do i have to have main.cpp free the dll, and have second.cpp load the dll like main already did?
Printable View
ok i have main.cpp which loads functions from a dll
have another second.cpp
how do i use functions from main.cpp in second.cpp
or do i have to have main.cpp free the dll, and have second.cpp load the dll like main already did?
There are some variations depending on your target system and build environment, but generally speaking.
1) Place declarations in a header file (say, main.h) of functions in main.cpp
2) #include "main.h" in second.cpp, preferably after #include'ing any standard header files.
3) Within second.cpp, call functions declared in main.h to your hearts content. Ensure you get types of function arguments, return types, and calling conventions right (note: if you have not specifically monkeyed with calling conventions, the only requirement to get calling conventions right is to use compatible compilers).
4) When building the executable, ensure the object files (main.o and second.o) are both included in the link. If usage of main.cpp requires use of a particular library, then also include that library in the link.
If your intent is to directly call functions in the DLL, then second.cpp needs to use the same technique as main.cpp does.
I've kept my answer generic - if you want a specific answer to your situation, you need to be specific in your question.
ok, just have the dll i am calling the functions in/from so no header
when i do the exact as main.cpp in the seond.cpp i get errors that they are already defined in main.obj.
basically i am using a vellman k8055 card, with its supplied dll
in main i have it loading the dll and taking the functions from it, like opencard();
but in the second.cpp (a dialog box) i need to use for example SetDigitalChannel();
how do i get second.cpp to use the function that main.cpp already "loaded"?
i am used to single source console programs, i am jumping into gui with multiple CPP and UI files in QT....
good news is i did manage to find out how to get dialog to send an int back to main!!!
That means you are duplicating function definitions (i.e. both source files implement a particular function). Remove the duplicates from one of your source files, recompile, and relink.
Beyond that, you will need to read the documentation that came with your card and DLL. Generally, it makes no difference how many object files call functions in a DLL - as long as the linker can resolve the calls (or, if you are dynamically loading the DLL, your program can resolve functions at run time - but, from what little you have described, you are not doing that).
well the functions are being called in main.cpp, and working, but i dont know how to call the functions in main.cpp FROM my second.cpp
Did you actually read my first post?
yeah
1 dont have a header, no idea how to make a header from a dll. although i would love to strip out a dll and just place the functions right into my program instead of using a dll
2 when i try to call everything in main and in second, i get duplication errors
other then that, no idea what to do.
You don't make a header file from a DLL, and you don't need to - and I never suggested you need to. If a header file is needed to use a DLL, they will be supplied together - and, to get main.cpp working with it, you would have used that already if needed.
You stated that you are seeking to call functions in main.cpp from second.cpp. To support that, you create - with your text editor or IDE, a header file with the appropriate function declarations (so the compiler has visibility of the function declarations when compiling both source files). Then you ensure that the functions are only implemented in one of the source files, not in both - if you don't do that, you get error messages about duplicated symbols from the linker. A function entry point is associated with a symbol. If you implement a function twice, the symbol is duplicated.
The fact that main.cpp is using the DLL is absolutely irrelevant.
The real problem is that you are just hacking together your main.cpp and second.cpp. They way you're doing it would get the same problem (duplicated symbols) even if you weren't using a DLL. It so happens main.cpp is using functions from a DLL, and you are assuming "oh, the problem is with the DLL, not the way I've hacked things".
well not hacking together, main.cpp is the main, second is the dialog box where you can "choose" an address for the connection to the card. trying to get the dialog to check if it can open the card, and if not warn the user, if so then open card and then close the dialog. Main will be doing all the functions, just need to pass the "opendevice" function to the dialog.
never said any prob was with the dll, just back to orig question, how do i call the function in main, from the second.cpp (the dialog).
making the declarations of the functions in a header sounds like it will work, and will try it asap.
thank you
That "orig question" is exactly what I answered in the second post of this thread. You're the one who kept associating things (in your opening posts, and subsequent replies) with the DLL, as if that was causing some other difficulty - at the same time as providing other information that indicated the DLL wasn't causing your problem.
Hoorah.
If main.cpp is implementing the "opendevice" function, then all that is needed is for the compiler to see a declaration of "opendevice" when compiling second.cpp. A header file providing said declaration is a common technique to achieve that.
If "opendevice" is a variable (say, a pointer to a function that main.cpp obtains from the dll) then the same answer applies. A declaration of "opendevice" in a header file, which is #include'd by both main.cpp and second.cpp, is sufficient.
In other words, the first post I made in this thread provided the answer.
ok made header
in main.cpp, before the main codeCode:intOpenDevice(intCardAddress);
voidCloseDevice();
intSearchDevices();
intSetCurrentDevice(intlngCardAddress);
intVersion();
intReadAnalogChannel(intChannel);
voidReadAllAnalog(int*Data1,int*Data2);
voidOutputAnalogChannel(intChannel,intData);
voidOutputAllAnalog(intData1,intData2);
voidClearAnalogChannel(intChannel);
voidClearAllAnalog();
voidSetAnalogChannel(intChannel);
voidSetAllAnalog();
voidWriteAllDigital(intData);
voidClearDigitalChannel(intChannel);
voidClearAllDigital();
voidSetDigitalChannel(intChannel);
voidSetAllDigital();
boolReadDigitalChannel(intChannel);
intReadAllDigital();
voidResetCounter(intCounterNr);
intReadCounter(intCounterNr);
voidSetCounterDebounceTime(intCounterNr,intDebounceTime);
intReadBackDigitalOut();
voidReadBackAnalogOut(int*Buffer);
after mainCode:#include"relaypanel.h"
#include"ui_relaypanel.h"
#include<QApplication>
#include<QtCore>
#include<QtGui>
#include<windows.h>
#include"cardselect.h"
#include"k8055.h"
typedefvoid(CALLBACK*t_func)(int);
typedefvoid(CALLBACK*t_func0)();
typedefint(CALLBACK*t_func1)();
typedefvoid(CALLBACK*t_func2)(int*,int*);
typedefvoid(CALLBACK*t_func3)(int,int);
typedefint(CALLBACK*t_func4)(int);
typedefbool(CALLBACK*t_func5)(int);
t_func4OpenDevice;
t_func0CloseDevice;
t_func0Version_;
t_func4ReadAnalogChannel;
t_func2ReadAllAnalog;
t_func3OutputAnalogChannel;
t_func3OutputAllAnalog;
t_funcClearAnalogChannel;
t_func0ClearAllAnalog;
t_funcSetAnalogChannel;
t_func0SetAllAnalog;
t_funcWriteAllDigital;
t_funcClearDigitalChannel;
t_func0ClearAllDigital;
t_funcSetDigitalChannel;
t_func0SetAllDigital;
t_func5ReadDigitalChannel;
t_func1ReadAllDigital;
intinit(void);
HINSTANCEhDLL;
inth=init();
in second.cppCode:intinit(void)
{
hDLL=LoadLibrary((LPCWSTR)L"k8055d");
if(hDLL!=NULL)
{
OpenDevice=(t_func4)GetProcAddress(hDLL,"OpenDevice");
if(!OpenDevice)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
CloseDevice=(t_func0)GetProcAddress(hDLL,"CloseDevice");
if(!CloseDevice)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ReadAnalogChannel=(t_func4)GetProcAddress(hDLL,"ReadAnalogChannel");
if(!ReadAnalogChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ReadAllAnalog=(t_func2)GetProcAddress(hDLL,"ReadAllAnalog");
if(!ReadAllAnalog)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
OutputAnalogChannel=(t_func3)GetProcAddress(hDLL,"OutputAnalogChannel");
if(!OutputAnalogChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
OutputAllAnalog=(t_func3)GetProcAddress(hDLL,"OutputAllAnalog");
if(!OutputAllAnalog)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ClearAnalogChannel=(t_func)GetProcAddress(hDLL,"ClearAnalogChannel");
if(!ClearAnalogChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ClearAllAnalog=(t_func0)GetProcAddress(hDLL,"ClearAllAnalog");
if(!ClearAllAnalog)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
SetAnalogChannel=(t_func)GetProcAddress(hDLL,"SetAnalogChannel");
if(!SetAnalogChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
SetAllAnalog=(t_func0)GetProcAddress(hDLL,"SetAllAnalog");
if(!SetAllAnalog)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
WriteAllDigital=(t_func)GetProcAddress(hDLL,"WriteAllDigital");
if(!WriteAllDigital)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ClearDigitalChannel=(t_func)GetProcAddress(hDLL,"ClearDigitalChannel");
if(!ClearDigitalChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ClearAllDigital=(t_func0)GetProcAddress(hDLL,"ClearAllDigital");
if(!ClearAllDigital)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
SetDigitalChannel=(t_func)GetProcAddress(hDLL,"SetDigitalChannel");
if(!SetDigitalChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
SetAllDigital=(t_func0)GetProcAddress(hDLL,"SetAllDigital");
if(!SetAllDigital)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ReadDigitalChannel=(t_func5)GetProcAddress(hDLL,"ReadDigitalChannel");
if(!ReadDigitalChannel)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
ReadAllDigital=(t_func1)GetProcAddress(hDLL,"ReadAllDigital");
if(!ReadAllDigital)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
Version_=(t_func0)GetProcAddress(hDLL,"Version");
if(!Version_)
{// handle the error
FreeLibrary(hDLL);
return-2;
}
return0;// ok
}
return-1;// error load DLL
}
Code:#include"cardselect.h"
#include"ui_cardselect.h"
#include"k8055.h"
#include<QtCore>
#include<QtGui>
intcard;
CardSelect::CardSelect(QWidget*parent):
QDialog(parent),
ui(newUi::CardSelect)
{
ui->setupUi(this);
}
CardSelect::~CardSelect()
{
deleteui;
}
voidCardSelect::on_comboBox_highlighted(intindex)
{
card=index;
}
voidCardSelect::on_pushButton_clicked()
{
if(OpenDevice(card)==-1)
QMessageBox::critical(0,"Failure","Card not attached or not set for address "+QString::number(card));
}
tons of errors,
alot of
error: C2365: 'OpenDevice' : redefinition; previous definition was 'function'
for each function
and all left operand because of functions.
either i missed something, or i have too much something! lol
ok tried making a header, and even included a header from the company.
still having probs.
my relaypanel (dialog, source and header) loads the dll, and functions of the dll, then calls cardselect (dialog, source and header)
how do i use a function, in this case opendevice, in the cardselect dialog.
tried declaring functions in header, and calling them from relaypanel, then including same header in cardselect, it doent know what the functions are OR screaming already declaired
"If your intent is to directly call functions in the DLL, then second.cpp needs to use the same technique as main.cpp does."
tried that and it screams duplicate also....
this all works as a single CPP, with a single UI, and also works as a single CPP in Console.
as soon as i add a dialog to do the card address selection, the functions dont carry over.
When writing in C++, take advantage of that. Every single one of those FreeLibrary calls can be eliminated by using RAII. Just create a little smart class and put FreeLibrary in the destructor.
ok, i will start over with everything....
Created a new GUI Application with QT
selected DIALOG
default files made are
dialog.h
dialog.cppCode:#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
main.cppCode:#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
Code:#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
now in my main.cpp, i add my dll loading files, and add dll to folder and use command to open the card at address 0
end up with main.cpp like this
Code:#include "dialog.h"
#include <QApplication>
#include <QtCore>
#include <QtGui>
#include <windows.h>
typedef void(CALLBACK* t_func)(int );
typedef void(CALLBACK* t_func0)();
typedef int(CALLBACK* t_func1)();
typedef void(CALLBACK* t_func2)(int *, int *);
typedef void(CALLBACK* t_func3)(int , int );
typedef int(CALLBACK* t_func4)(int );
typedef bool(CALLBACK* t_func5)(int );
t_func4 OpenDevice;
t_func0 CloseDevice;
t_func0 Version_;
t_func4 ReadAnalogChannel;
t_func2 ReadAllAnalog;
t_func3 OutputAnalogChannel;
t_func3 OutputAllAnalog;
t_func ClearAnalogChannel;
t_func0 ClearAllAnalog;
t_func SetAnalogChannel;
t_func0 SetAllAnalog;
t_func WriteAllDigital;
t_func ClearDigitalChannel;
t_func0 ClearAllDigital;
t_func SetDigitalChannel;
t_func0 SetAllDigital;
t_func5 ReadDigitalChannel;
t_func1 ReadAllDigital;
int init(void);
HINSTANCE hDLL;
int h = init();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
int foundDLL = 0;
//Check if DLL was found and loaded//
if (!h)
{
foundDLL = 1;
}
else
{
QMessageBox select;
select.windowTitle()="Error";
select.critical(0, "Critical", "K8055D.DLL NOT FOUND\nExiting program");
ExitProcess(1);
}
//open card at address 0 //
int Card = 0;
if (foundDLL)
{
if(OpenDevice(Card) == -1)
{
QMessageBox::critical(0,"Failure!!!","Card not attached or not set for address "+QString::number(Card));
ExitProcess(9); // no card
}
if(OpenDevice(Card) != -1)
QMessageBox::information(0,"Success!!!","Card attached on address "+QString::number(Card));
}
w.show();
return a.exec();
CloseDevice();
FreeLibrary(hDLL);
}
int init(void)
{
hDLL = LoadLibrary((LPCWSTR)L"k8055d");
if (hDLL != NULL)
{
OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice");
if (!OpenDevice)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
CloseDevice = (t_func0) GetProcAddress(hDLL, "CloseDevice");
if (!CloseDevice)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ReadAnalogChannel = (t_func4) GetProcAddress(hDLL, "ReadAnalogChannel");
if (!ReadAnalogChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ReadAllAnalog = (t_func2) GetProcAddress(hDLL, "ReadAllAnalog");
if (!ReadAllAnalog)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
OutputAnalogChannel = (t_func3) GetProcAddress(hDLL, "OutputAnalogChannel");
if (!OutputAnalogChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
OutputAllAnalog = (t_func3) GetProcAddress(hDLL, "OutputAllAnalog");
if (!OutputAllAnalog)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ClearAnalogChannel = (t_func) GetProcAddress(hDLL, "ClearAnalogChannel");
if (!ClearAnalogChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ClearAllAnalog = (t_func0) GetProcAddress(hDLL, "ClearAllAnalog");
if (!ClearAllAnalog)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
SetAnalogChannel = (t_func) GetProcAddress(hDLL, "SetAnalogChannel");
if (!SetAnalogChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
SetAllAnalog = (t_func0) GetProcAddress(hDLL, "SetAllAnalog");
if (!SetAllAnalog)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
WriteAllDigital = (t_func) GetProcAddress(hDLL, "WriteAllDigital");
if (!WriteAllDigital)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ClearDigitalChannel = (t_func) GetProcAddress(hDLL, "ClearDigitalChannel");
if (!ClearDigitalChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ClearAllDigital = (t_func0) GetProcAddress(hDLL, "ClearAllDigital");
if (!ClearAllDigital)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
SetDigitalChannel = (t_func) GetProcAddress(hDLL, "SetDigitalChannel");
if (!SetDigitalChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
SetAllDigital = (t_func0) GetProcAddress(hDLL, "SetAllDigital");
if (!SetAllDigital)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ReadDigitalChannel = (t_func5) GetProcAddress(hDLL, "ReadDigitalChannel");
if (!ReadDigitalChannel)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
ReadAllDigital = (t_func1) GetProcAddress(hDLL, "ReadAllDigital");
if (!ReadAllDigital)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
Version_ = (t_func0) GetProcAddress(hDLL, "Version");
if (!Version_)
{ // handle the error
FreeLibrary(hDLL);
return -2;
}
return 0; // ok
}
return -1; // error load DLL
}
Then after run, this laods the dll, gets the functions, connects to the card, then opens the dialog..
NOW i want to control the card with dialog....
so in dialog.cpp how would i call the functions main.cpp loaded?
i just need to use lets say
to turn on relay 1, how would i call that function from the dialog.cpp?Code:SetDigitalChannel(1);
i hope this makes more sense, as it is NOT HACKED together, there is nothing wrong with the dll, nothing wrong with the program, as it runs fine from main.cpp, just need to use the function loaded form the dll at runtime in dialog...
so nothing?
When it comes to this board I hardly get an answer I understand, but a little while ago I learned to google the words I didn't understand to their responses and this led me to the answer as some subjects they mention encompass a lot of knowledge. It at least shows a willingness to understand the answers you are given.
Where I am at now I usually get a buzz word like "quaternion" or "SLERP". While the poster has the knowledge of the subject they hardly have the time to explain its every use and implementation. Without them showing me these words though i would spend days trying to find a solution to my poorly worded google search! Lol
That being said I have seen you progress on this project for a while and you definitely show an aptitude for learning. I have not really messed around with qt or controllers yet, as I continue to live a fantasy that I may one day be a game designer.
https://www.google.se/search?q=raii
Also, as for destructor and smart class, go read a little about classes.
I thank you Lesshardtofind, when i started doing this type of automation, it was in dos batch files, Basic,console programs and parallel ports!! Windows seemed to make things more difficult once they blocked direct access to ports starting in i believe windows 2000/xp. Decided to but the vellman k8055 board as a usb interface, as it installs as a HID, and doesnt need any "special" software, or drivers. and in console still works for me almost like the parallel ports used to. BUT then i decided to use GUI and touchscreen to control 320 relays. Still have alot to learn of course, and jumping right into it (like i do most things!) i have already learned alot. And if i kep to just one dialog box, or just one script, still works. long way to go though!
ELYSIA, thank you, read up on RAII, and smart pointers, as well as a little on destructor. so far, not as helpful with my program that i can see so far. STILL tryng to really understand classes, as well as how it would help with sharing a function. Classes still a little confusing!
ill keep going with it, and hopefully it will work!
thanks all
well started reading classes, went right over my head!!!
also started reading about function pointers, also kinda lost...
I think you have a tendency to take a huge project to solve a small problem. That backfires. If you encounter a problem, build the smallest compilable example and solve your problem there, then transfer your solution.
In this case, your problem is calling a function from one cpp file in another cpp file. No QT, no external dll, nothing. Just two cpp files. Make a new project, add 2 cpp files and solve your problem. Only when it's solved, transfer your solution back to your huge project.
Somebody already told you above but I will try to rephrase that:
main.cpp
other.cppCode:int main()
{
}
int function(int x)
{
return x*2;
}
This will not compile as you already found out. Because you are missing a prototype of "function" in other.cpp. To make sure this prototype is the same across all cpp files, we put those prototypes in extra files called headers.Code:void other_function(int z)
{
return function(z) + 17;
}
function_header.h
Now both files need to know that this header exists so you need to #include it. AddCode:int function(int x);
to the top of your other.cpp file. Now it should compile.Code:#include "function_header.h"
If I were you I would just spend more time on it. There is no rule that says you have to get something right away. I think it took me a week to get the right collision algorithm for walking on sloped surfaces.Quote:
well started reading classes, went right over my head!!!
I can say from my past that every program I wrote in c++ without classes was poorly written and poorly designed. The moment you understand classes your programs will immediately become more organized and hopefully more re-usable as well. As for function pointers I really have only used them when required by a windowing interface like GLUT.
I agree with nvgoit on the fact that you seem to be overcomplicating the solution. Sometimes it helps to take a step back from coding and researching and just sketch out a map of all your functions (and classes eventually) and how they interact with each other. In the long run thinking about everything and asking yourself questions like. "Do these really need to interact?". "Does x NEED to know about y?".
Is going to lead to better design, input to output flow, and less unforeseen bugs. Some things just have to be learned as you go, but I promise that when you "get" classes you will never look back.
ok your header and 2 cpp`s worked. but that is because in the CPP`s, the functions are defined.
unfortunatly i cannot "define" the functions i am using from the dll, because i do not know them!!! just how to call them
and when i try to do the header, exact to what you showed
Code:intOpenDevice(intCardAddress);
and included the headers in both sources, i get:
L:\relaydlltest1\main.cpp:16: error: C2365: 'OpenDevice' : redefinition; previous definition was 'function'
refuring to
andCode:t_func4OpenDevice;
l:\relaydlltest1\Functions.h:5: see declaration of 'OpenDevice'
going right to
i dont understand how i am "overcomplicating the solution", when i have yet to have a solution. i did exactly what both of you said. Make a header that declares the function, and then include it in both sources....Code:intOpenDevice(intCardAddress);
i did that, and get the same errors i been saying from the start....
any simplier not "overlycomplicating" idea???
You have named your functions and variables alike. Give them proper names and your compiler error will vanish.
t_func4 is a bad name. Tells nothing. How about function_OpenDevice_t or t_func_OpenDevice?
OpenDevice as variable is a bad name because it's already taken. How about DynamicallyLoadedFunction_OpenDevice?
And your function to excute that DynamicallyLoadedFunction_OpenDevice could be named CallOpenDeviceFromLibrary. That is the only part that needs to go in the header file.
OK started over with a simple opendevice
functions.h
main.cppCode:#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include <iostream>
#include <Windows.h>
typedef int(CALLBACK* t_func4)(int );
t_func4 OpenDevice;
#endif // FUNCTIONS_H
dialog.cppCode:#include "dialog.h"
#include <QApplication>
#include <windows.h>
#include <iostream>
#include <QDebug>
#include "functions.h"
int init(void);
HINSTANCE hDLL;
int h = init();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
int init(void)
{
hDLL = LoadLibrary((LPCWSTR)L"k8055d");
if (hDLL != NULL)
{
OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice");
if (!OpenDevice)
{ // handle the error
FreeLibrary(hDLL);
return -2;
qDebug() << h;
}
return 0; // ok
}
return -1; // error load DLL
}
Errors as followsCode:#include "dialog.h"
#include "ui_dialog.h"
#include "functions.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
OpenDevice(0);
}
Dialog::~Dialog()
{
delete ui;
}
dialog.obj:-1: error: LNK2005: "int (__stdcall* OpenDevice)(int)" (?OpenDevice@@3P6GHH@ZA) already defined in main.obj
debug\dlltest2.exe:-1: error: LNK1169: one or more multiply defined symbols found
ALOT less errors, then again i am only trying to load/call one function from dll....
i know it is something simple i must be missing....
and hard to know what to change/edit as
1) using the supplied DLL to send to the PIC with custom boot
2) trying to edit there "demo" and "sample" code
3) have no idea how to work with multiple sources (like stated before i have always only used 1 source file)
i learned to program on my own, with help from others here and there when it came to something i never knew.
so i understand the "i am not doing it for you" which i love. but i do need more then just a "read the book" type answer as the "books" i have found, are no help with this!
a broke down simple example would be freaken great instead of 4 days of VERY general answers, even after stating i have no idea how to write headers, very vague idea of how to load a DLL (as i learned from 40 different pages, which all had something different) to be honest, i am getting sick of the "try this" with my reply of "nope", then "well you need to fix it" with my reply being "how" and the response "i already told you, with a header" it has become a 4 day never ending circle. Even when i teach in lab, when people have tried, i atleast break it down to simple terms that they (who have NEVER programmed before) can understand. Well with the DLL`s, Headers, Multiple sources, QT Creator, 4 things i have NEVER used untill about a week ago, i need a little more explination of what the hell i am doing....
oh and not to forget, following the "MAKE A DLL AND USE IT" lessons
i made a DLL, and then including both the headers, trying to load it, all i ever got was
L:\MyLib-build-Desktop-Debug\debug\MyLib.dll:-1: error: LNK1107: invalid or corrupt file: cannot read at 0x2C8
and that was using the same headers that made the dll, so making a header for a dll so that i can use a function call no matter where i call it in the application is driving me nuts, i have rewrote this program about 15 different times, atleast 15 different ways, and end up with the same result, or worse.
so honestly, no, nothing here has seemed helpful.
Unfortunately, that is how many things are. There are really never clear answers. There are only bits and pieces. You have to puzzle them together. Yes, I know it is frustrating, but you have to get used it because this is not the last time you'll have to deal with it.
Anyway, some general pointers and what is going wrong.
In functions.h, you have:
t_func4 OpenDevice;
And this is your problem. You've declared a global variable, which is included in both .cpp files. This mean you have two variables with the same name that are globals. That is an error and that is why you get an error saying it is already defined.
The fix? The best fix is to avoid global variables altogether. Failing that, you need to define the variable in one and only one .cpp file. Then, in the header, declare it as
extern t_func4 OpenDevice;
This essentially tells the compiler that it should not define a variable (because of "extern"), but also at the same time tells the compiler that it exists, but in another source file. So, so long as you have defined it in one source file, it will not complain.
Now, some general pointers:
Based on that, an improved version of the code might be:Code:int init(void) // Using "void" when no arguments are needed is just an ugly relic from C. You can get rid of it.
{
hDLL = LoadLibrary((LPCWSTR)L"k8055d"); // Avoid global variables as much as possible. Don't cast strings.
if (hDLL != NULL) // This is an anti-pattern. Use if (!hDLL), then terminate.
{
OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice");
if (!OpenDevice) // Same here. Anti-pattern.
{ // handle the error
FreeLibrary(hDLL); // Cleanup should be done via RAII
return -2;
qDebug() << h; // This will never get executed.
}
return 0; // ok
}
return -1; // error load DLL
}
Some of this code requires C++11 (see sig).Code:int init() // Using "void" when no arguments are needed is just an ugly relic from C. You can get rid of it.
{
HINSTANCE hDLL = LoadLibrary(L"k8055d");
if (!hDLL)
return -1;
OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice");
std::shared_ptr<void*> _(nullptr, [hDLL](void*) { FreeLibrary(hDLL); });
if (!OpenDevice)
return -2;
return 0; // ok
}
extern t_func4 OpenDevice; killed the error, like i said, i knew it was something simple i was missing, and that your for explainging what it does also!
the void, and the debug, a few to many CTRL-Z while i was "editing"
will work on fixing the globals, and i dont use them unless i have to. This was all just slap together to figure out my error. Thank you VERY much
//EDIT//
ok now confused, worked, then second run, it didnt, undid the EXTERN so that it wasnt there anymore, and now it runs.....WTH?
//edit 2//
now it doesnt work with or without extern
//Edit 3//
ok fixed edit 1 and 2, now to find out why it runs.....then crashes!
Crossfire, I can understand that this is quite frustrating. C++ isn't easy. But you need to start with the small (or not so small) basics like header files and classes. A project that dynamically loads a dll in a cross platform gui framework is way out of your league if classes and RAII aren't in your reach yet.
I'll take a wild guess and say that you have no idea what this line does:
And that's ok. It's freaky stuff. But you cannot base your program on something that you don't understand. That simply won't work.Code:std::shared_ptr<void*> _(nullptr, [hDLL](void*) { FreeLibrary(hDLL); });
For example, if I'm not mistaken, that line tells me that the library will be unloaded at the end of the init function when the shared_pointers destructor (after making sure it was the only reference) calls the lambda expression. So your global variable with the function pointer will propbably be invalid after init.
I will repeat my advice: divide and conquer. Your program fails and you don't know why. Make your problem set smaller. You tackled multiple cpp files and headers. Now forget about multiple files and your Gui framework. Can you write the smallest possible program dynamically loading your dll and calling a function? If you can, combine the solutions.
yeah and i agree, i already can load and have loaded the dlls, just never knew how to make them "global" for the entire application.
and i agree, i started small, have an entire programs in C, C++, and Windows forms to do this. Just trying to "port" it over to gui now using QT!
and once i had that one running in only one form, owith nce source, i decided to make it span accross dialogs. starting with just opening the device in a new dialog.
being able to call the function from the new dialog is where i was stuck. But i do that all of you for helping so far!
sorry for my fustration, been beating my skull against the keyboard! lol
and your right, i have yet to study/use the c++11 yet, so didnt have a clue to what that did!
rewrite from the start, using my new "functions.h" file....everything works great, "extern" was the "key" i was looking for! GREAT explination also Elysia!
All DLL loaded functions work perfect from any form now!
all 321 buttons, and 642 labels work perfect (visible true/false labels)
OpenDevice works perfect in the Select Device dialog now that i dont have to return selection to main, then if error, re exec the dialog.
Also a note on classes, i can see why they seem "complicated to learn", and also why they would be "better" to use. The set up like a struct, and "section" everything into easy bits to pass, use, etc!
Thank you all.
next step, develope a "server" and "client" version so i can run hardware on one machine (or just off my router/switch) and control from the Client! but i am a LONG way from that. Need to learn alot more about classes, then of course the c++ network programming "stuff"
this "project" started with
parallel port, using the 8 data outputs and 2 control outputs
dos direct control
batch file
c console
c++ console
parallel port using 8data 2 control to "steer" data through flip flops and 3x8 decoders
c console
c++ console
usb interface (vellman 8055 kit) 8 data 2 control though flip flops and decoders
c++ console
Windows forms ( worked, but sucked!)
and finally thanks to your help here, using QT for GUI controls!!!
last 2 years been "interesting"
images of the selector, and panel
very basic looking
combo box for address picking, pushbuttons for all 320 relays, 2 labels, one "red light" and one "green light" for relay on and relay off.
Attachment 12467Attachment 12468
yups, made a boo boo....desktop is high res, laptop with touchscreen is only 800x600!!! got some resizing to do! lol