Daten von DLLs abrufen ohne Speicherverletzung
-
Moin,
ich habe leider kein richtiges Unterforum dafür gefunden, deshalb habe ich mein Problem mal hier gepostet.
Ich arbeite mit einem Freund an einer Application in Verbindung mit Kinect.
Er ist ein VB Programmierer und ich bin C++ Progger.Da er aber kein C++ kann und ich C++ jedoch sehr schätze, wollen wir versuchen das mit 2 Sprachen über die Bühne zu bringen. Deshalb schreibe ich meinen Code in eine DLL, damit er sie dann zur Laufzeit einbinden kann. Mir ist klar, dass das Haufen von potenziellen Fehlern enthalten kann und in Verbindung mit einem Beta SDK nicht die beste Idee ist, jedoch hoffe ich das es trotzdem lösbar ist.
Meine Funktionen sind alle öffentlich und lauten:
int _stdcall KinectInit(){/*****/} int _stdcall startGame(){/*****/} int _stdcall getData(char* a,char* b, char* c){/*****/} int _stdcall exitGame(){/*****/} int _stdcall KinectShutdown(){/*****/}
Mein .def lautet:
EXPORTS KinectInit; Initialisert Kinect getData; Gibt Daten über PPP zurück KinectShutdown; Beendet Kinect startGame; Startet ID Registrierung exitGame; deregistriert
Und in VB eingebunden sieht das dann so aus:
Private Declare Function getData Lib "KinectControl.dll" (ByRef a As Byte, ByRef b As Byte, ByRef c As Byte) As Integer Private Declare Function KinectInit Lib "KinectControl.dll" () As Integer Private Declare Function KinectShutdown Lib "KinectControl.dll" () As Integer Private Declare Function startGame Lib "KinectControl.dll" () As Integer Private Declare Function exitGame Lib "KinectControl.dll" () As Integer
getData wird proFrame aufgerufen und gibt 3Bytes zurück.
Ich habe jedoch das Problem, dass ich ab und an (machmal auch immer) eine System.AccessViolationException bekomme. Meiner Einschätzung nach handelt es sich nicht um "Coder-Fehler" auf einer der beiden Seiten, sondern hat wohl andere Gründe.Ich hatte eine Zeit lang mal C-Strings zurückgegeben. Da hat schon
return "0800800";
diese Exception ausgelöst. Beim folgenden Code gab es aber keine Exception:
char test[] = "08000800"; char* tmp = test; return tmp;
Dann dachte ich, der Fehler würde daran liegen, dass der return Wert als Wert ohne Variable unterwegs verloren geht. Daraufhin habe ich es auf Referenz/Zeiger Basis mit etwas Speicheroptimierung eingebaut (siehe oben). Aber dann geht's manchmal, manchmal auch nicht.
Habt ihr vllt eine Idee woran es liegen könnte? Ich versuche es gerade einfach testweise mal immer in eine Datei zu schreiben und dann von dort wieder lesen zu lassen damit ich mir die von mir nicht kontrollierte Übergabe erspare. Dann werde ich vllt auch ausschließen können, dass es etwas mit der Kinect zu tun hat oder eben doch. Kennt ihr denn noch andere Möglichkeiten Daten zu versenden, damit ich mir dann gegf. meinen Ersatzstream (=txt) sparen kann?
Ich kann auf jeden Fall sagen, dass die Exception geworfen wird, bevor der VB Code etwas weiteres ausführt.
Ich hoffe ihr seht, dass ich mich um Fehlersuche bemühe und hoffe auf viele Ratschläge :).
Gruß Mark
-
Ein kleines Update:
Nach der Umstellung auf die TextStreams läuft das Programm nun viel stabiler, es tritt dieException im Normalfall nicht auf, nur unter bestimmten Umständen auf. Aber daran arbeite ich noch.
Vielelicht hilft das ja noch dem ein doer anderen bei seiner Fehleranalyse. Der Fehelr muss zwischen DLL und Programm passieren, schätze ich.
Wenn ihr noch gute Vorschläge habt wie man den "TextStream" ersetzen könnte, dann immer her damit.
Gruß, Mark
-
Sehr gute Fehlerbeschreibung, so von außen ist es natürlich trotzdem noch schwierig, den Fehler zu bestimmen.
Häufige Fehler sind ja falsch angegebene Signaturen - deine angegebenen sind aber stimmig zu deinen Funktionen.
Dass die Exception unregelmäßig auftaucht, ist beunruhigend.
Hast du nicht evtl doch einen Bug in deinem C++-Code, mit dem du z.B. evtl den Stack zerschießt?
-
Danke.
Also ich habe zumindest alle Pointer ausgebaut, sodass da kein "wilder" Zeug durch die Gegend schießen dürfte. Das war auch mein Gedanke als ich dieses hier las:
http://msdn.microsoft.com/en-us/library/system.accessviolationexception(v=vs.80).aspx
(Siehe Remarks)Ansonsten wüsste ich nicht, was da noch schief gehen könnte, werde aber morgen mal den Codeausschnitt posten.
Gruß, Mark
EDIT: Code doch jetzt
//Globale Konstanten zu Testzwecken... int null = 0; int m_eins = 1; int _stdcall getData() { //Ein Frame derKinect NUI_SKELETON_FRAME SkeletonFrame; HRESULT hr = NuiSkeletonGetNextFrame(10,&SkeletonFrame); //Mein TextFrame std::fstream out("Datastream.kcs"); out.clear(); //Kein neuer Frame if(hr<0) { out<<102<<std::endl<<102<<std::endl<<null<<std::endl; out.close(); return m_eins; } //... //Position der linken Hand bekannt? if(SkeletonFrame.SkeletonData[LeftIndex].eSkeletonPositionTrackingState[NUI_SKELETON_POSITION_HAND_LEFT] ==NUI_SKELETON_POSITION_NOT_TRACKED) { out<<101<<std::endl<<101<<std::endl<<null<<std::endl; out.close(); return m_eins; } //linker Spieler mit linker Hand float TargetPlayerLeft; TargetPlayerLeft = SkeletonFrame.SkeletonData[LeftIndex].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT].y - SkeletonFrame.SkeletonData[LeftIndex].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_LEFT].y+0.4f; TargetPlayerLeft*=1.25; if(TargetPlayerLeft>1) TargetPlayerLeft=1; else if (TargetPlayerLeft<0) TargetPlayerLeft=0; TargetPlayerLeft=100-ceil(TargetPlayerLeft*100); //Sicher ist sicher if(TargetPlayerLeft>100) TargetPlayerLeft=100; else if (TargetPlayerLeft<0) TargetPlayerLeft=0; //Output //Spieler links std::stringstream str; if(TargetPlayerLeft<10) { str<<TargetPlayerLeft; char l = str.str().front(); out<<l<<std::endl; } else if(TargetPlayerLeft<100) { str<<TargetPlayerLeft; char tmp[] = {str.str()[0],str.str()[1]}; out<<(tmp[0]-48)*10+(tmp[1]-48)<<std::endl; } else { out<<100<<std::endl; } str.clear(); //Hier später Spieler rechts, deswegen doppelt. if(TargetPlayerLeft<10) { str<<TargetPlayerLeft; char l = str.str().front(); out<<l<<std::endl; } else if(TargetPlayerLeft<100) { str<<TargetPlayerLeft; char tmp[] = {str.str()[0],str.str()[1]}; out<<(tmp[0]-48)*10+(tmp[1]-48)<<std::endl; } else { out<<100<<std::endl; } out<<0<<std::endl; out.close(); return null; }
Es gibt viele Sachen die auf den ersten Blick ziemlich sinnfrei daherkommen, sind aber noch überbleibsel aus alten Tests, dürfte aber nichts zur Sache tun.
-
Ein paar Kommentare oben ergänzt.
-
Habe das Problem gelöst. Es war ein Fehler meinerseits, der dazu führte, dass in seltenen Fällen eine Variable uninitialisiert kopiert wurde.
Gruß, Mark