LabVIEWForum.de - Fehlercode 1097 beim Aufrufen einer C++ DLL

LabVIEWForum.de

Normale Version: Fehlercode 1097 beim Aufrufen einer C++ DLL
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Seiten: 1 2
Hallo LabVIEW-Forum Wink2,

ich habe diese Frage bereits im NI-Forum gestellt: Beitrag im NI-Forum jedoch bisher keine Antwort erhalten.

Daher hoffe ich, dass mir vielleicht hier jemand weiterhelfen kann.

Beim Aufruf einer C++ DLL zur Kommunikation mit einem Controller eines Profilprojektors erhalte ich den Fehler 1097, da die übergebenen Parameter wahrscheinlich nicht korrekt sind.
[attachment=62260]

VI lv19_img; .DLL; Header-Datei; Beschreibung der Funktion und Parameter sowie Screenshots sind in einer .zip-Datei beigefügt.

Die Rückgabewerte von Funktionen, die mit dem Controller kommunizieren, sind immer vom Typ ReturnCode (die enum Definition des Fehlercodes).
In der Header-Datei ist ReturnCode definiert als:

enum class ReturnCode
{
RC_ERR_NONE = 0x0000,
RC_ERR_COMMUNICATION_NONE = 0x1000,
RC_ERR_CHECKSUM = 0x1001,
RC_ERR_LENGTH = 0x1002,
RC_ERR_VERSION = 0x1003,
RC_ERR_COMMAND = 0x1004,
RC_ERR_TIMEOUT = 0x1005,
RC_ERR_UNABLE_TO_EXECUTE = 0x2001,
RC_ERR_PART_FAILURE = 0x2002,
RC_ERR_OUT_OF_BOUND = 0x2003,
RC_ERR_INVALID_PARAM = 0x3001,
RC_ERR_INVALID_OPERATION = 0x3002,
RC_ERR_NOT_FOUND = 0x3003,
RC_ERR_INVALID_TARGET = 0x3004,
RC_ERR_ALREADY_EXISTS = 0x3005,
RC_ERR_MEMORY_ALLOCATION_ERROR = 0x3006,
RC_ERR_NO_SPACE = 0x3007,
RC_ERR_SDCARD_NOT_FOUND = 0x3008,
RC_ERR_WRITE_PROTECTED = 0x3009,
RC_ERR_READ_ONLY = 0x3010,
RC_ERR_HEAD_NOT_FOUND = 0x3011,
RC_ERR_FAIL = 0x3012,
RC_ERR_OUTPUT_ERROR = 0x3013,
RC_ERR_OVERFLOW_IMAGE_MEMORY = 0x3014,
RC_ERR_NO_USB_HDD = 0x3015,
RC_ERR_USB_WRITE_PROTECTED = 0x3016,
RC_ERR_BUFFER_SIZE = 0x5000,
RC_ERR_UNKNOWN = 0xF000,
};

Der Import der DLL-Funktionen mit dem Import Shared Library Wizard ist nicht möglich, da die folgenden Symbole nicht definiert sind: ReturnCode.
[attachment=62263]

Also habe ich versucht, eine einfache Funktion (USB-Verbindung mit Controller herstellen) nur mit Returncode und ohne Parameterübergabe aufzurufen.

Das Format der Funktion zum Verbinden der USB-Kommunikation ist:
ReturnCode TMXIF_OpenUsbCommunication();
[attachment=62262]

Mein Funktionsaufruf über Call Library Function:
int32_t TMXIF_OpenUsbCommunication (void);
[attachment=62261]

Ich habe auch verschiedene Rückgabetypen ausprobiert oder Calling convention stdcall, erhalte aber immer den Fehler 1097.

Ich gehe davon aus, dass ich die Funktionen der DLL nicht aufrufen kann, da der Rückgabewert als "ReturnCode" definiert ist und deshalb der Funktionsaufruf nicht ohne weiteres in LabVIEW möglich ist.

Ich habe diesen Beitrag gefunden, in dem beschrieben wird, dass in diesem Fall zum korrekten Aufrufen der DLL eine Wrapper DLL geschrieben werden muss:
What is a Wrapper DLL and When Do I Need One?

Ich habe leider absolut keine Ahnung von C++ und konnte keine Beispiele finden, wie man eine Wrapper-DLL schreibt. Huh
Mir ist bewusst, dass die Erstellung einer Wrapper-DLL keine einfache Sache ist (vorallem für jemanden ohne Vorkenntnisse), aber irgendwo muss ich anfangen um weiterzukommen.
Außerdem wäre es gut zu wissen, ob die Ursache für den Fehler 1097 tatsächlich der ReturnCode ist oder ob ich einen anderen Fehler mache.

Ich wäre sehr dankbar für jede Hilfe oder Erklärung, die mich bei dem Problem weiterbringt. Smile
Hallo Dr. Nuke,

herzlich willkommen im LabVIEW-Forum!

Zitat:Die Rückgabewerte von Funktionen, die mit dem Controller kommunizieren, sind immer vom Typ ReturnCode (die enum Definition des Fehlercodes).
Ich bin kein C(++)-Experte, aber die Items des Enums sehen aus wie UInt16-Werte…
(Das hilft bei diesem CLFN aber auch nicht weiter.)

Zitat:Beim Aufruf einer C++ DLL
Hier solltest du die Meinung eines C++-Experten (wie RolfK) abwarten…
Hallo Dr. Nuke,

der datentyp des enum wurde nicht explizit festgelegt und damit ist nicht zwingend festgelegt was das ist. Praktisch dürfte es jedoch ein int sein, also in der Regel wohl ein 32 Bit Integer.

Es scheint mir aber ziemlich egal zu sein. Schließlich ist das erst einmal "nur" der Rückgabewert der DLL.
Der Return Wert als Int32 wird im Prozessorregister EAX zurückgeliefert und wenn du den falschen Typ nimmst (Int16 oder Int64) dann wird das AX oder RAX Register verwendet. Du bekommst etwas zurück. Entweder es sind 16 Byte zu wenig (Int16) oder 32 Byte zu viel (Int64). Du kannst auch einfach "void" angeben, da passiert auch nichts.

Könnte es sein, dass das Problem an einer anderen Stelle liegt? Die DLL scheint nicht sehr rebust zu sein. Wenn ich die hier aufrufe (den darunter liegende Treiber habe ich nicht), dann bleibt das Programm bis in alle Ewigkeit in der DLL stecken. Die DLL sollte in dem Fall mit einer Fehlermeldung zurück kommen. Ich nehme deshalb an, dass die DLL auch in anderen Fällen kein sauberes Verhalten zeigt.

Davon ganz abgesehen: Wenn du alle Funktionen nutzen willst, dann wird das ohne eine Wrapper DLL etwas schwierig. Wenn du nur einen Teil der Funktionen benötigst, dann geht es evtl. auch ohne.

BTW. Ich kann nicht einmal ReturnCode TMXIF_GetDllVersion(TMXIF_VERSION_INFO* versionInfo); ausführen. Auch dabei hängt sich die DLL schon auf.
Vielen Dank für die schnellen Rückmeldungen. Smile

(15.07.2022 14:17 )Martin.Henz schrieb: [ -> ]Könnte es sein, dass das Problem an einer anderen Stelle liegt? Die DLL scheint nicht sehr rebust zu sein. Wenn ich die hier aufrufe (den darunter liegende Treiber habe ich nicht), dann bleibt das Programm bis in alle Ewigkeit in der DLL stecken. Die DLL sollte in dem Fall mit einer Fehlermeldung zurück kommen. Ich nehme deshalb an, dass die DLL auch in anderen Fällen kein sauberes Verhalten zeigt.
Also die Version der DLL ist 1.0.0, deshalb kann es durchaus sein, dass sie noch nicht vollständig ausgereift ist.
Es gibt auch 2 Beispielprogramme zur DLL inklusive Quellcode (siehe Sample.zip im Anhang), einmal programmiert in CPP und einmal in CS. Die Programme funktionieren bei mir mit angeschlossenem Controller und Profilprojektor einwandfrei, deshalb müsste die DLL robust funktionieren. Nur kann ich sie in LabVIEW nicht korrekt einbinden.

(15.07.2022 14:17 )Martin.Henz schrieb: [ -> ]BTW. Ich kann nicht einmal ReturnCode TMXIF_GetDllVersion(TMXIF_VERSION_INFO* versionInfo); ausführen. Auch dabei hängt sich die DLL schon auf.
Ich habe auch versucht, verschiedene Funktionen aufzurufen. Bei mir dauert es ca. 3 Sekunden und dann bekomme ich immer Error 1097.

(15.07.2022 14:17 )Martin.Henz schrieb: [ -> ]Davon ganz abgesehen: Wenn du alle Funktionen nutzen willst, dann wird das ohne eine Wrapper DLL etwas schwierig. Wenn du nur einen Teil der Funktionen benötigst, dann geht es evtl. auch ohne.
Ich werde nicht alle Funktionen benötigen. Es gibt eine Software, in der Programme bereits erstellt werden können. Ich muss über LabVIEW dann "nur" die Ergebnisse mit dem Befehl ReturnCode TMXIF_GetResult auslesen.

Aber dazu muss zuerst überhaupt mal die Verbindung mit dem Controller funktionieren. Wacko
upps ...
erst mal danke für das Beispiel, wenngleich ich jetzt erst einmal lauter Fragezeichen sehe :-)

Ich gehe mal zu dem Abschnitt mit Aufruf von TMXIFCLR::TMXIF_GetDllVersion(&versionInfo), denn das sollte ja auch problemlos
funktionieren.


Zitat: TMXIFCLR::TMXIF_VERSION_INFO versionInfo = {};
001BAB79 xor eax,eax
001BAB7B mov dword ptr [versionInfo],eax
001BAB7E mov dword ptr [ebp-28h],eax
001BAB81 mov dword ptr [ebp-24h],eax

Ja gut, drei 32 Bit Integer für die DLL-Version, in die Integer schreibt der Compiler 0 rein (nicht nötig, aber ok).

Nun wird die Adresse der Version auf den Stack geworfen, dann folgt der Funktionsaufruf.

Zitat: const auto returnCode = TMXIFCLR::TMXIF_GetDllVersion(&versionInfo);
001BAB84 mov esi,esp
001BAB86 lea eax,[versionInfo]
001BAB89 push eax
001BAB8A call dword ptr [__imp__TMXIF_GetDllVersion (01E8250h)]
001BAB90 add esp,4
001BAB93 cmp esi,esp
001BAB95 call __RTC_CheckEsp (014ECB6h)
001BAB9A mov dword ptr [returnCode],eax

Am Ende wird der Returncode vom Register EAX ausgelesen (ein 32 Bit Integer).

Soweit ist das alles genau so wie ich es erwarte hatte.

Ich bin gerade etwas ratlos, das ist ja nicht so kompliziert...
Zuerst einmal vielen Dank für die Unterstützung.

(15.07.2022 21:48 )Martin.Henz schrieb: [ -> ]Am Ende wird der Returncode vom Register EAX ausgelesen (ein 32 Bit Integer).

Soweit ist das alles genau so wie ich es erwarte hatte.

Ich bin gerade etwas ratlos, das ist ja nicht so kompliziert...

Das bedeutet, der Rückgabewert sollte ein 32 Bit Integer sein und der Funktionsaufruf in LabVIEW
Zitat:int32_t TMXIF_OpenUsbCommunication (void);

ist soweit auch korrekt, aber es ist bisher nicht nachvollziehbar, warum es nicht funktioniert?

Habe ich das soweit richtig verstanden?
Hi Dr. Nuke,

ja korrekt - es ist noch viel schlimmer.

Wenn ich eine (einfache) Konsolenanwendung erstelle und z.B. die Funktion TMXIF_GetDllVersion aufrufe, dann funktioniert es ohne Fehler.
Mache ich das exakt identisch innerhalb einer Wrapper-DLL, welche anschließend von LabVIEW aus aufgerufen wird, dann poppt der C++ Debugger mit einem Fehler auf, dass nun in kernelbase.dll etwas komplett schief läuft.

Ich habe nicht die geringste Ahnung, was diese TMXIF DLLs machen, dass sich das derart komisch verhält.

Nachtrag: Bevor Nachfragen kommen: Wenn ich meine Wrapper-DLL aus der Konsolenanwendung heraus aufrufe, funktioniert es auch.
Hi Dr. Nuke,

es ist zwar ziemlich krank, aber eine Lösung über den Umweg einer Konsolenanwendung scheint möglich: Du erstellst eine Konsolenanwendung, welche mit deinem Programm Daten austauschen kann (z.B. über TCP/IP, Memory Mapped File oder auch normale Dateien).
Hi Martin.Henz,

vielen Dank für die Erklärungen und den möglichen Lösungsansatz. Ich konnte aber nun eine andere Lösung finden.

Da die Einbindung der DLL über „Call Function Libraray Node“ nicht funktioniert hat, hatte ich die Idee die Funktionen über den „.NET constructor“ aufzurufen.
Leider wusste ich nicht, welches der richtige Constructor dafür ist (große Auswahlmöglichkeit an Objects und Constructors im Assembly).
Habe nun vom Hersteller den notwendigen Constructor mitgeteilt bekommen [TMXIFClass()].

Damit funktioniert jetzt alles einwandfrei, habe auch schon die ersten Messwerte eingelesen.

VI lv19_img zur Verbindung mit dem Controller und zum Auslesen der DLL-Version ist mit im Anhang für die Leute die ebenfalls Interesse an der Lösung haben.
Ohne Controller wird aber immer der Fehler "RC_ERR_COMMUNICCATION_NONE" erscheinen.

Da dies mein erster Beitrag im Forum ist sollte ich nun diesen Beitrag (meinen eigenen) als Lösung markieren?
Hi Dr. Nuke,

(21.07.2022 15:20 )Dr. Nuke schrieb: [ -> ]Da dies mein erster Beitrag im Forum ist sollte ich nun diesen Beitrag (meinen eigenen) als Lösung markieren?

gar nichts markieren ... das ist ja nicht die Lösung zur Eingangs gestellten Frage. Dort war ja nicht die Rede davon, dass es auch noch eine .NET Schnittstelle gibt.
Seiten: 1 2
Referenz-URLs