Probleme beim Freigeben von SAFEARRAY
-
Da stimmt so ziemlich gar nichts. Wenn Du SafeArrayUnaccessData aufrufst, sagst Du, dass Du mit dem von SafeArrayAccessData gelieferten Pointer fertig bist und nicht mehr darauf zugreifen willst. Das ist aber nicht das, was Du tatsächlich willst. Dann kannst Du natürlich auch nicht einfach delete auf irgendwelche Pointer aufrufen. Räume Dein VARIANT mit VariantClear auf. Intern wird dann korrekt SafeArrayDestroy aufgerufen was dann bei Bedarf auch SafeArrayDestroyData für Dich aufruft.
Lese aber am Besten erstmal die Dokumentation zu SAFEARRAYs. Du scheinst eben gar nicht zu wissen, womit Du das hier zu tun hast.
-
Danke für eure Hinweise...
so in die Richtung hab ich auch schon was gelesen... da hast du vollkommnen recht... ich hab keinen Schimmer mit was ich es hier zu tuen hab ;-)... das Problem is halt, dass der Code nich von mir kommt, ich ihn aber benutzen muss...
also das mit dem VariantClear hab ich schon mal gelesen.Zum einen will die VariantClear Funktion ein VARIANTARG haben
Wie kann man das konvertieren?
Und zum Anderen hab ich mal was gelesen, dass bei arrays die
variantclear funktion nix bringen würde... wenn ich die stelle
noch mal finde poste ich sie... vlt hab ich das aber auch falsch interpretiert
-
OK...
ich habe jetzt mal an die Stelle von den deltes
VariantClear(&res);
gesetzt...
und den unaccessdata teil aus der getData auskommentiert...
muss jetzt mal testen wie der speicher sich verhältgebe dann noch mal bescheid
-
also das UnaccessData muss drinbleiben sonst
kann er den kram scheinbat net löschen...das programm läuft auf jeden fall jetzt mal durch...
nur bin ich mir net so ganz sicher ob der speicher richtig
freigegeben wird... hab das gefühl als hätte das unter xp
mit den deletes besser gewirkt...
-
Natürlich kann das Array ohne SafeArrayUnaccessData nicht abgeräumt werden. Aber so, wie Du es machst, ist es schlicht falsch. Du machst doch in etwas dieses hier:
float* getData(VARIANT in) { float HUGEP *out = new float[123]; delete [] out; return out; }Ohne delete läuft Dir selbstverständlich der Speicher voll, aber was nützt Dir der Pointer nach dem Verlassen der Funktion?
-
ja ich hab schon verstanden, dass das jetzt so ähnlich is wie der code den du gepostet hast. Aber irgendwie scheint es trotzdem zu funktionieren...
also diese
env->SetFloatArrayRegion(outArray, 0, peaks, intensities); env->SetFloatArrayRegion(outArray, peaks, peaks, masses);koppieren die daten von intensities und masses in das outarray damit
dieses an Java zurückgegeben werden kann.Also deiner meinung nach müsste ich das Unaccesdata eigentlich direkt vor dem VariantClear machen und nach allen operationen die mit dem array zu tuen haben...
richtig?das tolle is dann nur, dass ich den kompletten code durchgucken muss weil
derjenige der diesen kram gecodet hat, nutzt diese getData geschichte ja in der
ganzen DLL... so ein mist.aber wieso bekomme ich keine probleme im moment beim zugriff auf das array?
obwohl es ja mit unaccessdata "unbrauchbar" gekennzeichnet wird?
-
SafeArrayAccessData und SafeArrayUnaccessData bilden ein Sandwich.
D.h.
1. Du rufst AccessData auf.
2. Du änderst/benutzt Daten
3. Du rufst UnaccessData auf.Wenn die Get Funktion kein Unaccess aufruft, dann musst Du es dort fixen und nicht bei jedem Aufruf.
So sollte es es sein!
Ein Array der gelocked ist kann weder zerstört noch pre Redim bearbeitet werden.
-
Habe den Code jetzt folgendermaßen abgeändert:
JNIEXPORT jfloatArray JNICALL Java_dbLib_ReadBinaryFile_getSpectrum (JNIEnv *env, jclass jc, jstring file, jlong scan, jint func) { //COM-Objekt initialisieren CoInitialize(NULL); IDACSpectrumPtr pSpectrum = IDACSpectrumPtr(CLSID_DACSpectrum); //Javastrings parsen const char* c_file = env->GetStringUTFChars(file, 0); jfloatArray outArray; //benötigte Variablen VARIANT res; long peaks; float *intensities, *masses; //Anzahl der Datenpunkte bestimmen und Array initialisieren peaks = getDataPoints(c_file, func, scan); outArray = env->NewFloatArray((int)peaks*2); //Daten lesen pSpectrum->GetSpectrum(c_file, func, 0, scan); pSpectrum->get_Intensities(&res); intensities = getData(res); pSpectrum->get_Masses(&res); masses = getData(res); //Daten in ein JavaArray kopieren env->SetFloatArrayRegion(outArray, 0, peaks, intensities); env->SetFloatArrayRegion(outArray, peaks, peaks, masses); //Aufräumen env->ReleaseStringUTFChars(file, c_file); freeData(res); return outArray; } /* Die Methode entpackt ein float-Array aus einem VARIANT*/ float* getData(VARIANT in) { float HUGEP *out; SafeArrayAccessData(in.parray,(void HUGEP**)&out); return out; } /* Die Methode räumt einen Variant auf*/ void freeData(VARIANT in) { SafeArrayUnaccessData(in.parray); VariantClear(&in); }Aber der Speicher läuft mir trotzdem voll...
Irgendwie löscht er das nicht richtig...
Jemand nen Vorschlag?
-
Ach mist... Ich glaub ich hab da en array vergessen... Muss ich morgen mal testen
-
Dein Code kann nicht funktionieren.
1. Musst Du klären ob get_Intensities und get_Masses ein In/Out oder ein out als Argument nimmt.
2. SOllte es ein out sein, dann wird der SafeArray des ersten Variants nicht gelöscht. Und Du hast in jedem Fall den letzten Variant nicht freigegeben.
3. Grundsätzlich musst Du VARIANTs Du Du als Ergebnis bekommen hast mit VariantClear löschen.
4. Nachdem Du den ertsen VARIANT geholt hat, führt die zweite Verwendung des selben Variants zum Zerstören des ersten VARIANT, dieser Array kann nie freigegeben werden.Ich rate Dir dringend etwas mehr über COM zu lernen.
-
vielen dank für eure mühe und auch noch mal für den letzten post...
das mit dem zweiten variant is mir dann auch gestern erst in den sinn gekommen...
deswegen sprach ich von nem zweiten array was ich vergessen habe...
ist halt bissl unglücklich gecodet die dll... vlt hätte ich sie von anfang überabrieten sollen...wüsste nicht wieso ich was über com lernen sollte.. finde dafür in der regel keine verwendung. mein projekt ist in java und ich muss halt ne die blöde dll benutzen die schon da is... und jetzt nur extra dafür meine zeit zu opfern mir wetierhin com anzuscheuen sehe ich im moment kein bedarf...

Also Jemand könnte diesen Thread dann als gelöst markieren....
-
ErdyMurphy schrieb:
wüsste nicht wieso ich was über com lernen sollte.
Weil Du COM hier extrem benutzt. Ob das nun ene DLL ist oder nich spielt keine Rolle. Und bei COM gibt es Calling Conventions.
Dazu gehört, dass man ein VARIANT, das man bekommen hat auch brav mit VariantClear freigibt.
oder genauso, dass ein VARIANT mit VariantInit vorblegt wird bevor man es an eine Funktion übergibt (BTW das fehlt in Deinem Code).
Das wäre nur erlaubt, wenn die Funktion diesen VARANT als out definiert hat.
Guter Stil ist es immer VariantInit aufzurufen.