Pointer auf InProc COM Server in zweiter dll benutzen
-
Hi Jochen,
ich denke eigentlich nicht, dass das JNI irgendetwas damit zu tun hat.
Ich habe trotzdem mal die Beispielfunktion von dieser MSDN Seite in meiner dll ausprobiert und das hat problemlos geklappt. (Rücksprung nach Java klappt auch problemlos, wenn ich entweder die Zeile mit der Exception auskommentiere, oder die Exception aus VC++ Express heraus einfach quittiere.)
Das Problem scheint meiner Meinung nach viel mehr zu sein, dass ich nicht auf die Methode
get_Item()
zugreifen kann. Diese ist ja in meinem Treiber COM-Server implementiert.
Meine Wrapper dll habe ich mit dem Parameter __stdcall kompiliert. Die COM Architektur benutzt diese Calling Convention auch so weit ich informiert bin. Trotzdem scheint sich hier ein Problem zu ergeben (zwischen meiner dll und dem COM InProg Server).Hat denn schon einmal jemand etwas ähnliches versucht?
Nochmal, das der Aufruf in Zeile 29 erfolgreich war spricht ja sehr dafür, dass ich schon das richtige Objekt im Speicher anspreche. Wie gehe ich nun vor, dass ich eine vom Objekt implementierte Interface Methode aufrufen kann?
Hat denn hier jemand Erfahrung mit dem ganzen IVI Kram? Da hätte ich nämlich auch noch ein paar Fragen drüber.
Gruß,
Maik
-
Wo genau tritt denn der Fehler auf? Beim Rücksprung von get_Item oder beim Rücksprung aus Deiner Methode?
Aus meiner Sicht ist das Problem (wie es auch in der Fehlermeldung heisst) eine falsche Calling-Convention...
Ich hab schn Agilent angebunden... zwar nur das Multimeter...
-
Hi,
der Fehler tritt genau in Zeile 37 auf. Das heißt, ich setze einen Breakpoint auf Zeile 37, gehe einen Schritt weiter, quittiere die Exception-Meldung im Debugger und springe dann wieder ins Java programm zurück, dass ganz normal weiterläuft( weil ich dort den rückgabewert NULL abfange).
Du hast also schon eimal ein Agilent Multimeter angebunden, okay . . .
Hast du das mit dem IVI-COM oder mit dem IVI-C Treiber gemacht?
Wie gesagt, ich arbeite ja gerade mit IVI-COM, weil die Infos auf der "IVI Foundation" Webseite und auch alle anderen Ressourcen suggerieren, dass man dann "Interchangebility" erreichen kann. Aufgrund dessen wird auch immer wieder empfohlen, dass man den COM Treiber benutzen soll und nicht den C-Treiber.
Äußere Umstände, die ich auch nicht ändern kann, zwingen mich nun dazu das Oszilloskop in eine Java App einzubinden. Da ich gerne die "interchangebility" erreichen möchte Mühe ich mich nun mit COM ab.
Ich frage mich aber z.B. immer, warum, wenn von "interchangebility" die Rede ist, die COM Beispile aus dem Treiberpaket im Sourcecode immer den Namen des Agilent Oszilloskops benutzen. Das wird dann mit einem Oszilloskop der Firma Tektronix nicht ohne weiteres zu ersetzen sein.
Wie erreiche ich denn nun die "Interchangebility"?
Ich habe auf der IVI Foundation Webseite etwas über eine "Ivi Session Factory" gelesen, mit der das wohl zu erreichen sei. Leider finde ich keine eindeutigen Beispiele in diese Richtung und habe das Gefühl, dass man eine Menge Hintergrundwissen benötigt, um diese ganze IVI Spezifikation zu verstehen.
Kannst du mir da weiterhelfen?Gruß,
Maik
-
Für die COM-Interfaces kann es keine unterschieldiche Calling Convention geben.
Evtl. sind Deine Interface Definitionen falsch und passen nicht zu der installierten Software.Hast Du die TLB direkt aus dem COM Objekt ausgelesen?
-
Hi Martin,
schön, dass sich noch andere für dieses Thema interessieren . . .
Also, dass ich prinzipiell auf dem richtigen COM Objekt im Speicher operiere meine ich in Zeile 29 verifiziert zu haben.
Wenn ich dort nämlich
QueryInterface
aufrufe, und dieIID
des gesuchten Interfaces übergebe und anschließendS_OK
zurück bekomme, so kann ich doch davon ausgehen, dass dem Code an dieser Stelle genau dieses Interface bekannt ist und es sich somit um mein gesuchtes Objekt handelt.Dass ich hier auch noch keine "Calling Convention" Exception bekommen habe lässt mich auch vermuten, dass diese Laufzeitmeldung evtl. irreführend ist, weil es sich gar nicht um genau diesen Fehler handelt, sondern vom Debugger nur dafür gehalten wird.
Aus diesem Grund habe ich die Überschrift zu diesem Thread auch etwas allgemeiner gehalten.
Mir geht es vorrangig darum zu verstehen, ob und warum diese Methode zum Erfolg führen kann, oder eben nicht.
Gestern beim herumspielen (manchmal sieht man ja den Wald vor lauter Bäumen nicht) ist mir auch aufgefallen, dass mein Java Code nicht die das COM Objekt lädt, welches z.B. das
IIviScopeMeasurements
Interface anspricht (welches ich ja gerne wegen der oben schon genannten "Interchangebility" verwenden möchte), sondern einIAgilentU2701AMeasurements
Interface benutzt. Dieses Interface erbt sozusagen vonIIviScopeMeasurements
und sollte (damit es IVI kompatibel ist) auch die selbe Funktionalität anbieten.Das könnte schon mal erklären, warum bei meinem Codebeispiel besagte Zeile in die Hose geht.
Leider habe ich es auch mit diesem neuen Wissen nicht zum Laufen bringen können. . . .
Wie gesagt, ich würde mich freuen, wenn sich jemand an der Forschung beteiligen würde, da ja alle Ressourcen frei verfügbar sind, und das Thema (meiner Meinung nach) auch sehr interessant und lehrreich ist.
Ich bin mittlerweile bei dem Punkt angekommen, dass ich JNI Wrapper um den IVI-C Treiber schreiben werde, da ich nicht absehen kann, ob meine IVI-COM Versuche zum Erfolg führen werden. Allerdings werde ich die Forschung an dieser Stelle parallel weiter betreiben.
Gruß,
Maik
-
BSTR ch1 = L"CHANNEL1"; //... hr = measurementsPtr->get_Item(L"CHANNEL1", &measurementPtr);
Darf/muss/kann ich davon ausgehen, dass der erste Parameter von get_Item auch ein BSTR ist?
Wenn ja, dann mach dich auf eine ÜBLE Überraschung gefasst: ein Wide-Character String, wie du da einen übergibst, IST KEIN BSTR!Ein BSTR hat nämlich an Position ptr[-1] noch die Länge abgespeichert.
Dass BSTR nur ein Typedef auf wchar_t* ist, ist eine ÜBEL ÜBEL schlimme Design-Entscheidung von MS, die so manchem Programmierer so manches graue Haar beschert haben wird.
Wenn du nen BSTR willst, nimm entweder die MSVC Hilfsklasse _bstr_t, oder verwende SysAllocString.
Also z.B.#include <comutil.h> //... hr = measurementsPtr->get_Item(_bstr_t(L"CHANNEL1"), &measurementPtr);
Bin mir grad nicht sicher ob das dein Problem erklären kann, aber versuchs mal. Und merk dir auf jeden Fall das mit den BSTRings, wenn man mit COM rummacht braucht man das öfters.
-
Hi,
ja, du kannst davon ausgehen, dass es ein
BSTR
ist.Dies ist die Prototypdefinition aus der *.tlh Datei:
virtual HRESULT __stdcall get_Item ( /*[in]*/ BSTR Name, /*[out,retval]*/ struct IAgilentU2701AMeasurement * * val ) = 0;
Du hast recht, dass meine Definition nicht der eines BSTR entspricht. Die habe ich aus einer Beispielapplikation, die dem Treiber beiliegt abgeguckt. Dort stehen die Zeilen:
IAgilentU2701AMeasurementPtr meas; spAgDrvr->Measurements->get_Item(L"CHANNEL1", &meas);
Da das so zur Laufzeit keinen fehler gibt habe ich gedacht, dass passt schon. . . .
Auf alle Fälle ein super Tip, den ich heute abend mal zu hause ausprobieren werde. Vielen Dank!
Gruß,
Maik
-
Hi,
nur zur Info:
Das
_bstr_t(L"CHANNEL1")
hat leider nichts an der Runtime Exception geändert . . .
Gruß,
Maik
-
Kiamur schrieb:
Also, dass ich prinzipiell auf dem richtigen COM Objekt im Speicher operiere meine ich in Zeile 29 verifiziert zu haben.
Wenn ich dort nämlich
QueryInterface
aufrufe, und dieIID
des gesuchten Interfaces übergebe und anschließendS_OK
zurück bekomme, so kann ich doch davon ausgehen, dass dem Code an dieser Stelle genau dieses Interface bekannt ist und es sich somit um mein gesuchtes Objekt handelt.Das mag ja sein, aber woher hast Du die Deifnitionen wie das Interface aussieht?
Per #import besorgt (dann wäre es aktuell), oder hast Du einen Headerdatei dafür? Oder gar selbst gebastelt?Dass ich hier auch noch keine "Calling Convention" Exception bekommen habe lässt mich auch vermuten, dass diese Laufzeitmeldung evtl. irreführend ist, weil es sich gar nicht um genau diesen Fehler handelt, sondern vom Debugger nur dafür gehalten wird.
Diese Meldung deutet einzig darauf hion, dass der Stack zerstört wird!
-
Hi Martin,
zuerst habe ich mit dem Header gearbeitet, der allerdings auch mit in dem aktuellen Treiber/API Paket entahlten ist. Deswegen gehe ich mal davon aus, dass er auch aktuell ist.
Dann habe ich ja gemerkt, dass ich nicht mit der COM Klasse des Agilent Scopes direkt gearbeitet habe, sondern mit der IVI COM Klasse (zu der ich eben den Header habe). Dies ist ja eigentlich der Weg, den ich gehen möchte (Stichwort "Interchangeability").
Die Agilent Scope Klasse erbt allerdings von dieser Klasse. Deswegen hat der AufrufQueryInterface
nach meinemIviScopeMeasurements
Interface wohl auch funktioniert.Naja, da ich das ja alles aus den bekannten Gründen nicht zum Laufen gebracht habe, habe ich mir anschließend per
#import
die Agilent Scope COM Klasse verfügbar gemacht. Leider hat an dieser Stelle schon der erste Schritt nicht funktioniert, nämlich das casten meines Pointers auf das InProc COM Objekt, den ich ja über die JNI Schnittstelle aus dem Java Programm (und von da aus dem Com4J Paket) übergeben bekam.
Ich habe keine Ahnung, warum ich an der Stelle, wo ich caste (also noch nicht einmal, wenn ich versuche auf das Agilent Scope Objekt zuzugreifen) schon eine Access Violation Meldung bekomme.
Wie gesagt, caste ich den Pointer auf ein IVI Scope Objekt, dann bekomme ich keine Access Violation Meldung.Irgendetwas habe ich noch nicht verstanden an der IVI Treiberarchitektur, bzw an COM . . .
Gruß,
Maik