Forum: PC-Programmierung QT- DLL dynamisch einbinden


von Magdalena M. (magdalena)


Lesenswert?

Hallo,

ich habe dasselbe Problem wie ein Nutzer in einem älteren Beitrag:

Beitrag ""nackte" DLL einbinden (Qt)"

Zitat: "Ich versuche eine .dll (von dem PC-Oszilloskope PCSGU250) in ein
Qt-Projekt einzubinden.

In der Zip vom Hersteller befindet sich keine .a .lib .def oder .h
sondern nur die .dll, eine .bit und ein paar Beispiele für delphi und
VS."

Anstatt Header, .lib, .def, etc zu erstellen, möchte ich die .dll gerne 
dynamisch mit QLibrary laden.
Hierfür, schätze ich, brauche ich ebenfalls den "extern-"C"-Befehl", 
weiß jedoch nicht, wo und wie ich diesen einsetzen soll.

Beispielsweise habe ich als ersten Test Folgendes versucht, um die dll 
einzubinden:

    QLibrary library("PCSGU250.dll");
    if(library.load())
    cout <<"Library loaded";

Hierbei kann QT die dll jedoch nicht finden.

Da ich mit dem dynamischen Laden einer dll über die QLibrary völlig 
unerfahren bin, freue ich mich über jegliche Hilfe und Hinweise!

Beste Grüße und vielen Dank,
Magdalena

von Mathias O. (m-obi)


Lesenswert?

Ich hab das auch schon versucht. Das blöde ist nur, dass man genau 
wissen muss, wie die Funktionen heißen und welche Parameter übergeben 
werden müssen.

von Andreas B. (andreasb)


Lesenswert?

Mathias O. schrieb:
> Ich hab das auch schon versucht. Das blöde ist nur, dass man genau
> wissen muss, wie die Funktionen heißen und welche Parameter übergeben
> werden müssen.

Genau, das ist ein allgemeines Problem, das lässt sich aber z.B. 
Problemlos mit dem Dependency Walker anschauen:

http://www.dependencywalker.com/

z.B. hier findet man den Passenden Screenshot:
http://1.f.ix.de/imagine/swvz-programme/F5a7iHuJWliMfQ074CMcBCx9lsw/content/Dependency-Walker.jpg

Der Rest ist etwas Fleissarbeit...

Edit:
Hier noch das Beispiel, die daten siehst du beim Dependency Walker, so 
musst du das dann im Code erfassen:
http://doc.qt.io/qt-4.8/qlibrary.html#resolve



mfg Andreas

: Bearbeitet durch User
von Mathias O. (m-obi)


Lesenswert?

Ist nur blöd, wenn die Dll in .Net geschrieben ist ;).

von Wurfwanze (Gast)


Lesenswert?

Mathias O. schrieb:
> Ist nur blöd, wenn die Dll in .Net geschrieben ist ;).

Ist sie aber nicht, es handelt sich um eine einfache Win32-DLL mit ca. 
20 Funktionen.

Mathias O. schrieb:
> Das blöde ist nur, dass man genau wissen muss, wie die Funktionen heißen
> und welche Parameter übergeben werden müssen.

Das steht doch alles in der Datei "Make your own software for the 
PCSGU250.pdf".

von Wurfwanze (Gast)


Lesenswert?

Abgesehen davon wäre es bei einer .NET-DLL ja noch einfacher, 
exportierte Funktionen zu verwenden (einfach die DLL als Referenz 
einbinden).

von Wurfwanze (Gast)


Lesenswert?

Ok, in C++ (nicht C++/CLI) natürlich nicht ... (verflixt, ich sollte 
mich einloggen).

von Mathias O. (m-obi)


Lesenswert?

Wurfwanze schrieb:
> Ist sie aber nicht, es handelt sich um eine einfache Win32-DLL mit ca.
> 20 Funktionen.

Meine nicht. Meine ist von Epson um einen Epson Roboter anzusprechen.
Hab ja nicht gesagt, dass ich es mit der selben Dll versucht habe.

Wurfwanze schrieb:
> Abgesehen davon wäre es bei einer .NET-DLL ja noch einfacher,
> exportierte Funktionen zu verwenden (einfach die DLL als Referenz
> einbinden).

Und das geht genau wie im Qt Creator?

von Magdalena M. (magdalena)


Lesenswert?

Hallo,

vielen Dank zunächst für die vielen Antworten!

Für die Funktionen habe ich eine Liste, weiß also, welche Funktionen 
enthalten sind. Muss ich diese Funktionen einzeln mit extern c oder so 
ähnlich einbinden oder geht das für mehrere Funktionen zugleich? Wie 
funktioniert in diesem Fall der extern C Befehl?

Die Antworten sind jedenfalls schon sehr hilfreich!! :)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Magdalena M. schrieb:
> Muss ich diese Funktionen einzeln mit extern c oder so ähnlich
> einbinden oder geht das für mehrere Funktionen zugleich? Wie
> funktioniert in diesem Fall der extern C Befehl?

Du brauchst Funktionspointer, für jede Funktion, die Du aufrufen 
möchtest, einen einzelnen.
Da die Aufrufe C-Code (und kein C++-Code) sind, also ohne "name 
mangling" arbeiten, musst Du Definition und gegebenenfalls Deklaration 
dieser Funktionspointer in "extern C"-Abschnitten durchführen.

von Magdalena M. (magdalena)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

wenn ich eine Header-Datei erstellen möchte mit den Informationen aus 
der Datei "Make your own software...", in der die Funktionen aufgeführt 
sind, wie muss ich da vorgehen?

Die Funktionen in der Datei sind nicht in C++ geschrieben, sondern für 
Delphi, gibt es dafür eine bestimmte Methode, sie umzuschreiben, sodass 
mit der .dll gearbeitet werden kann?

Mit dem Dependency Walker bekomme ich folgendes Ergebnis(siehe Bild), es 
werden mir also die Namen der verschiedenen Funktionen angezeigt, jedoch 
keine Datentypen für Variablen. Ist da noch etwas einstellbar?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Magdalena M. schrieb:
> jedoch keine Datentypen für Variablen. Ist da noch etwas einstellbar?

Nein, diese Informationen stehen in der DLL nicht drin, die musst Du der 
Dokumentation der DLL entnehmen.

von Magdalena M. (magdalena)


Lesenswert?

Ok, die .dll wird jetzt von Qt gefunden, jedoch erscheinen 
(logischerweise) zahlreiche Fehler, die folgendermaßen aussehen:

stray"\"Zahl"" in program
(mit einer beliebigen Zahl)

Was genau bedeutet dieser Fehler?

Habe jetzt noch keine Header und keine .lib eingebunden, da ich bei der 
Header nicht weiß, wie ich sie erstellen soll.

In der Dokumentation steht beispielsweise für eine Funktion:

PROCEDURE Start_PCSGU250: Boolean;

Wie muss ich im Header etwas zu dieser Funktion angeben?
Ist hier
void Start_PCSGU250(void);
korrekt?

Gibt es einen Weg, sich eine Header Datei erstellen zu lassen durch eine 
Software?
Ist es weiterhin norwendig, auch die lib einzubinden?

Vielen Dank schonmal :)

von physiker (Gast)


Lesenswert?

Schau doch z.B. hier:
http://forum.velleman.eu/viewtopic.php?f=10&t=8900
Andere Leute haben dieses Gerät auch...

von physiker (Gast)


Lesenswert?

Magdalena M. schrieb:
> PROCEDURE Start_PCSGU250: Boolean;
>
> Wie muss ich im Header etwas zu dieser Funktion angeben?
> Ist hier
> void Start_PCSGU250(void);
> korrekt?

Und da steht z.B. doch was von bool, warum also void?

von Flatsch (Gast)


Lesenswert?

Magdalena M. schrieb:
> In der Dokumentation steht beispielsweise für eine Funktion:
>
> PROCEDURE Start_PCSGU250: Boolean;
>
> Wie muss ich im Header etwas zu dieser Funktion angeben?
> Ist hier
> void Start_PCSGU250(void);
> korrekt?

Hmm ... Ich kenne Delphi nicht, aber ich würde mich fragen, warum dort 
Boolean steht und davon ausgehen, dass void/void nicht richtig sein 
kann ;). Und dann würde ich nachsehen, was PROCEDURE und FUNCTION 
bedeutet und mir eine Liste mit den Delphi-Datentypen und deren 
Eigenschaften suchen. Man könnte dann nachsehen und/oder sich überlegen, 
wie man die Datentypen in C übersetzt.

Magdalena M. schrieb:
> Gibt es einen Weg, sich eine Header Datei erstellen zu lassen durch eine
> Software?

Die Signaturen der Funktionen sind so simpel, dass das Schreiben der 
C-Funktionsprototypen nicht sooo schwierig sein dürfte. Aber physiker 
hat ja dir ja schon einen Link gegeben.

> Ist es weiterhin norwendig, auch die lib einzubinden?

Welche lib?

von Mathias O. (m-obi)


Lesenswert?

Weil du doch die .h oder .lib nicht hast, musst du doch QLibrary nehmen. 
Sonst könntest du ja auch den normalen Weg nehmen und das ganze über das 
pro-File einbinden.

Nun sollte es doch so einfach funktionieren:
1
QLibrary lib("PCSGU250.dll");
2
typedef bool (*protoBool)();
3
protoBool funcStart = (protoBool) lib.resolve("Start_PCSGU250");
4
if (funcStart)
5
    qDebug() << funcStart();

von Magdalena M. (magdalena)


Lesenswert?

Mathias O. schrieb:
> Weil du doch die .h oder .lib nicht hast, musst du doch QLibrary nehmen.
> Sonst könntest du ja auch den normalen Weg nehmen und das ganze über das
> pro-File einbinden.

In der Zwischenzeit konnte ich mir die .lib erstellen und versuche 
jetzt, die Header zu erstellen.


> Nun sollte es doch so einfach funktionieren:
>
1
QLibrary lib("PCSGU250.dll");
2
> typedef bool (*protoBool)();
3
> protoBool funcStart = (protoBool) lib.resolve("Start_PCSGU250");
4
> if (funcStart)
5
>     qDebug() << funcStart();


Mit diesem Code bekomme ich ebenfalls die Fehlermeldungen mit

 stray '\2' in program (mit verschiedenen Zahl hinter \)

Woher dieser Fehler kommt, konnte ich mir noch nicht erklären...

von Mathias O. (m-obi)


Lesenswert?

Dann brauchst du ja QLibrary nicht mehr und kannst den üblichen Weg 
gehen.

Hilft Google bei den Fehler nicht weiter?
https://www.google.de/#q=stray+%27\2%27+in+program

von Magdalena M. (magdalena)


Lesenswert?

Ja, ich versuche zumindest gerade, den normalen Weg zu gehen, scheitere 
aber wie gesagt an der Erstellung der Header, bzw. bin mir, was meine 
Header angeht nicht sicher. Das Problem ist eben dieser Fehler.

Hatte ihn, als ihn zum ersten Mal hatte, bereits gegooglet und nach 
einem ähnlichen Fall gesucht. Zumeist tritt dieser Fehler wohl auf, wenn 
Code per Copy&Paste übernommen wird, was bei mir nicht der Fall ist.

Zudem sagt die Fehlermeldung, die Fehler seien in der .dll aufgetreten, 
daher weiß ich nicht, wie ich dort etwas verändern soll...

von Mark B. (markbrandis)


Lesenswert?

Magdalena M. schrieb:
> Zudem sagt die Fehlermeldung, die Fehler seien in der .dll aufgetreten

Das glaube ich jetzt eher weniger. Die "stray irgendwas in program" 
Fehlermeldung kommt vom Compiler. Eine DLL ist bereits kompiliert, die 
wird dazugelinkt.

von The D. (thedaz)


Lesenswert?

Mark B. schrieb:
> Magdalena M. schrieb:
>> Zudem sagt die Fehlermeldung, die Fehler seien in der .dll aufgetreten
>
> Das glaube ich jetzt eher weniger. Die "stray irgendwas in program"
> Fehlermeldung kommt vom Compiler. Eine DLL ist bereits kompiliert, die
> wird dazugelinkt.

Vermutlich irgendwo im Source code versehentlich ein unsichtbares 
Sonderzeichen untergebracht. Sowas kann man in einem Hex-Editor finden 
und eliminieren.

von Rolf Magnus (Gast)


Lesenswert?

Vielleicht wird ja die DLL dem Compiler als Quellcodedatei verkauft. 
Dann könnte auch so eine Fehlermeldung kommen.
Wie sieht denn die komplette Meldung aus?

von Magdalena M. (magdalena)


Angehängte Dateien:

Lesenswert?

Die dll habe ich eingebunden, indem ich im .pro file den Pfad angegeben 
habe und in der main datei

include "PCSGU250.dll"

verwendet habe. Ich weiß nicht, ob dies der korrekte Weg ist oder die 
Datei so als Quellcode erkannt wird...

Die Fehlermeldung (also ein Beispiel) habe ich angefügt. Wenn ein 
Sonderzeichen der Grund ist, wie finde ich es dann it einem Hex Editor?
Bei 28000 dieser Fehler, sind es dann nicht viel zu viele Sonderzeichen?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Magdalena M. schrieb:
> include "PCSGU250.dll"

Das geht nicht. Das ist grundlegend und vollkommen falsch.

Lies ein C-Buch.
Sieh Dir an, was man mit #include einbinden kann.

von Mark B. (markbrandis)


Lesenswert?

Magdalena M. schrieb:
> include "PCSGU250.dll"

Aua :-)

Eine DLL kann man nicht inkludieren. Die wird vom Linker (das ist der, 
der nach dem Compiler drankommt) hinzugelinkt.

Ich kenne jetzt Deine Entwicklungsumgebung nicht. Aber irgendwo in den 
Projekteinstellungen gibt es sicher die Möglichkeit, dem Linker 
mitzuteilen dass er diese oder jene Datei hinzu linken soll. Das ist der 
Weg den Du wahrscheinlich gehen willst.

Bzw. wenn ich das hier lese:

Magdalena M. schrieb:
> In der Zip vom Hersteller befindet sich keine .a .lib .def oder .h
> sondern nur die .dll, eine .bit und ein paar Beispiele für delphi und
> VS.

dann fehlt ja gerade die .lib Datei zum Linken. Also muss man die DLL 
wohl dynamisch zur Laufzeit laden.

Nichtsdestotrotz sollte es in der Entwicklungsumgebung die Möglichkeit 
geben, den Pfad zu solchen Dateien anzugeben bzw. die 
Linker-Einstellungen mit entsprechenden Parametern zu ergänzen.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Mark B. schrieb:
> Also muss man die DLL wohl dynamisch zur Laufzeit laden.
> Nichtsdestotrotz sollte es in der Entwicklungsumgebung die Möglichkeit
> geben, den Pfad zu solchen Dateien anzugeben

Wozu? Wenn man sie dynamisch zur Laufzeit lädt, hat das mit der 
Entwicklungsumgebung nichts zu tun.

Aber um sie dynamisch zur Laufzeit zu laden, bedarf es Informationen 
über die in der DLL enthaltenen Funktionen, d.h. die 
Funktionsprototypen.

Es sei denn, diese DLL verwendet (D)COM-Automation und will 
"installiert", d.h. dem (D)COM-Gekröse von Windows bekanntgemacht 
werden.

Dann kann man die DLL mit jeder Sprache ansprechen, die 
Automationsobjekte anfordern und bedienen kann, also z.B. auch VBScript.

---
Nein, das ist nicht der Fall, das Ding verwendet keine Automation.

Bei der DLL handelt es sich um diese hier:

https://www.velleman.eu/downloads/files/downloads/pcsgu250_dll_rev1.zip

Das Ding ist in erster Linie für Delphi-Anwender beschrieben.

Codebeispiele sind für Delph und Visual Basic(.net) vorhanden.

Die verwendete VB.net-Version ist VB.net express 2008.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Magdalena M. schrieb:
> Die dll habe ich eingebunden, indem ich im .pro file den Pfad angegeben
> habe und in der main datei
>
> include "PCSGU250.dll"
>
> verwendet habe.

Damit wird klar, woher die Fehlermeldung kommt.

> Ich weiß nicht, ob dies der korrekte Weg ist oder die Datei so als
> Quellcode erkannt wird...

Wird sie. Der Präprozessor nimmt ihren kompletten Inhalt und fügt den so 
wie er ist an der Stelle, wo das #include steht, im Quellcode ein. Dann 
läuft der Compiler drüber, der damit natürlich nichts anfangen kann, 
weil es Binärdaten sind und kein C++-Code.

von Magdalena M. (magdalena)


Lesenswert?

Ok, ich habe meinen Fehler eingesehen. Das mit dem "include" war nur so 
eine spontane Idee von mir, da ich mir nicht bewusst war, dass er die 
Binärdaten dann als Quellcode einliest.
Habe es nun aber verstanden.
Meine Hoffnung war, dass dieser Weg irgendwie zielführend sei, da die 
.dll zumindest erkannt wurde, aber so ist ja jetzt klar, was passiert 
ist.

Zurzeit versuche ich weiterhin, die dll einzubinden mithilfe der aus der 
dll erstellten .lib und einer selbst erstellten Header-Datei.
Die .lib binde ich folgenderweise im .pro file ein:

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/./ -lPCSGU250

else:unix: LIBS += -L$$PWD/./ -lPCSGU250

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

Die Header-Datei binde ich in die .cpp mit include ein.

Die .dll habe ich jetzt unter DistFiles im .pro file eingebunden, bin 
mir da aber nicht sicher, ob das richtig ist, bzw. wie die .dll direkt 
eingebunden werden soll.

Ist dieser Weg soweit korrekt, bzw. was muss geändert werden?

von Meister Kleister (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe keine Ahnung von Qt, aber in VS wäre der einfachste Weg, sich 
per "dumpbin" und "lib" eine Library zu erstellen und diese sowie die 
(selbst geschriebene bzw. vom obigen Link abgewandelte) Header-Datei 
einzubinden. Die PCSGU250.dll muss natürlich im Ausgabeverzeichnis 
liegen, wenn das entsprechende Programm gestartet wird.

Das folgendes Programm stürzt zumindest nicht ab und gibt true und false 
aus. Das ist natürlich kein "Beweis" der Funktionsfähigkeit, aber mehr 
kann ich ohne die Hardware nicht testen.

1
#include <iostream>
2
#include "pcsgu250.h"
3
4
int main()
5
{
6
  std::cout << std::boolalpha << Start_PCSGU250() << std::endl;
7
8
  std::cout << DataReady() << std::endl;;
9
10
  return 0;
11
}

von Magdalena M. (magdalena)


Lesenswert?

Vielen Dank für die ausführliche und hilfreiche Antwort.

Passenderweise war gerade an genau dem Punkt angelangt, dass ich mir 
true und false Werte anzeigen ließ für die Start_PCSGU250() Funktion. :)
Die Antwort war aber trotzdem gut, damit ich weiß, dass mein Vorgehen 
soweit stimmt.

Hattest du die Header-Datei geschrieben oder wo kam sie her?
Sie deckt sich jedenfalls fast vollständig mit meiner erstellten 
Header-Datei, was mich schonmal beruhigt und das Anzeigen mit den true 
und false Werten funktioniert.

Das Einbinden von .h und .lib scheint auf jeden Fall zu klappen, mal 
schauen, wie es jetzt weitergeht :)

von Meister Kleister (Gast)


Lesenswert?

Magdalena M. schrieb:
> Hattest du die Header-Datei geschrieben oder wo kam sie her?

Ich habe bloß von hier
http://forum.velleman.eu/viewtopic.php?f=10&t=8900
kopiert (siehe Beitrag oben von 'physiker'), das .NET-Zeug gelöscht und 
extern "C" hinzugefügt. Ob alle Prototypen im Detail korrekt sind, habe 
ich aber nicht nachgeprüft.

von Magdalena M. (magdalena)


Lesenswert?

Achso, ja klar. Hatte mir diese Header-Datei angeschaut, aber war 
verwirrt durch die Zusätze mit "extern" in jeder Zeile und das Ganze mit 
DLL-Import. :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.