Probleme mit gcroot<T>
-
Hallo
Ich habe folgenden Beispielquellcode im Unterricht bekommen. Es ging die Anbindung einer MS Access DB mit Managed Klassen in WinForms...
TKfzAccessDB::TKfzAccessDB(String ^fileName) { SetFileName(fileName); String ^ ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"./kfz.mdb\""; //Datenbank-Spezifisches -> Verbindung zwischen Adapter und connection erzeugen, //das DataSet erzeugen OleDbConnection ^ conn = gcnew OleDbConnection(ConnectionString); //----------------------------------------------- //kommandos erzeugen und dem Adapter mitgeben OleDbCommand ^ cmdSelect = gcnew OleDbCommand("SELECT * FROM TMoto;",conn); //---------weitere Kommandos sind optional, zum lesen reicht select //die weiteren Kommandos werden später gesetz OleDbDataAdapter ^ adapterTMoto = gcnew OleDbDataAdapter(); adapterTMoto->SelectCommand = cmdSelect; //erst das DataSet fuellen DataSet ^dataSet = gcnew DataSet(); adapterTMoto->Fill(dataSet,"TMoto"); //DataSet ist gefüllt und hat eine Tabelle namens TMoto //und setzen this->SetAdapterTMoto(adapterTMoto); this->SetMyDataSet(dataSet); } void TKfzAccessDB::appendObject( Tkfz ^ kfz ) { } // ArrayList ^ lesenAusDataSet( String * tableName ) // Lese eine Tabelle aus dem Dataset in eine ArrayList ArrayList ^ TKfzAccessDB::lesenAusDataSet( String ^ tableName ) { ArrayList ^ retVal = nullptr; DataTable ^dt = this->GetMyDataSet()->Tables[tableName]; IEnumerator ^en = dt->Rows->GetEnumerator(); if (tableName == "TMoto") { retVal = gcnew ArrayList; while (en->MoveNext()) { DataRow ^row = dynamic_cast <DataRow ^> (en->Current); //und zerpfluecken int id = System::Convert::ToInt32(row["id"]); int baujahr = System::Convert::ToInt32(row["baujahr"]); int leistung = System::Convert::ToInt32(row["leistung"]); Tmotorrad ^ moto = gcnew Tmotorrad(id, row["name"]->ToString(), leistung, baujahr); retVal->Add(moto); } } //rueckgabe meiner Internen Liste return retVal; }
Allerdings arbeite ich gewohnter Weise mit der MFC und nicht mit WinForms. Daher musste ich mir Gedanken machen wie ich OLE in der MFC benutzen kann, also Managed Code in Unmanaged.
Ich erhielt den Rat, mich nach dem gcroot<> Template zu erkundingen. Ich habe die erste Methode dann mit Hile dieses Artikels umgeschrieben. Die erste Methode läuft auch Fehlerfrei, bei der zweiten erhalte ich allerdings einen Fehler, den ich mir weder erklären noch lösen kann.
//--------------------------------------------------------------------- #include <fstream> //--------------------------------------------------------------------- #include "cdb.h" //--------------------------------------------------------------------- #pragma push_macro("new") #undef new CDB::CDB(const string oFile) throw() { m_oFile = oFile; //Datenbank-Spezifisches -> Verbindung zwischen Adapter und connection erzeugen, //das DataSet erzeugen gcroot<OleDbConnection*> oConn; oConn = new OleDbConnection(S"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"./kfz.mdb\""); //kommandos erzeugen und dem Adapter mitgeben gcroot<OleDbCommand*> oCmd; oCmd = new OleDbCommand(S"SELECT * FROM TMoto;", oConn); //---------weitere Kommandos sind optional, zum lesen reicht select //die weiteren Kommandos werden später gesetz gcroot<OleDbDataAdapter*> oAdapterTMoto; oAdapterTMoto = new OleDbDataAdapter; oAdapterTMoto->SelectCommand = oCmd; //erst das DataSet fuellen gcroot<DataSet*> oDataSet; oDataSet = new DataSet; oAdapterTMoto->Fill(oDataSet, "TMoto"); //DataSet ist gefüllt und hat eine Tabelle namens TMoto //und setzen m_pAdapter = oAdapterTMoto; m_pDataSet = oDataSet; }; //--------------------------------------------------------------------- void CDB::lesen(const string oTable) throw() { gcroot<String*> tablename; tablename = new String("TMoto"); gcroot<DataTable*> oDataTable; oDataTable = this->getDataSet()->Tables[tablename]; // C2676 oDataTable = this->getDataSet()->Tables["TMoto"]; // C2107 }; #pragma pop_macro("new") //--------------------------------------------------------------------- gcroot<DataSet*> CDB::getDataSet(void) throw() { return m_pDataSet; }; //--------------------------------------------------------------------- //---------------------------------------------------------------------
Die Compilermeldung dazu:
error C2676: binary '[' : 'System::Data::DataTableCollection __gc *' does not define this operator or a conversion to a type acceptable to the predefined operator
error C2107: illegal index, indirection not allowed
Da google mit allen Möglichen Suchbegriffen keine Hilfe war und ich auch in anderen oder diesen Foren per Suchfunktion nichts gefunden habe, hoffe ich, dass mir nun jemand helfen kann.
Gruß, Kane
-
Wenn Du jetzt noch zeigst wo der Fehler im Quellcode auftritt...
[quote]Compilerfehler C2676
http://msdn.microsoft.com/library/deu/default.asp?url=/library/DEU/vccore/html/C2676.asp
Ratenderweise würde ich sagen:
GetMyDataSet()->Tables hat keinen passenden operator[] -> prüfe an dieser Stelle mal die Art und weise mit der Du zugreifst.
Ein gcroot Problem ist es imho nicht. (Zeig mal bitte die Zeile auf die sich der Fehler bezieht.)
-
Du bringst hier managed C++ und C++/CLI durcheinander!
Dein erstes Beispiel ist C++/CLI (VC2005), Dein zweites in managed C++ (das alte).
Ersetze also * durch ^
-
@knuddelbaer: habe doch bereits oben markiert, wo die beiden fehler auftreten, hier trotzdem nochmal der code ausschnitt
KaneMX schrieb:
//--------------------------------------------------------------------- void CDB::lesen(const string oTable) throw() { gcroot<String*> tablename; tablename = new String("TMoto"); gcroot<DataTable*> oDataTable; oDataTable = this->getDataSet()->Tables[tablename]; // C2676 oDataTable = this->getDataSet()->Tables["TMoto"]; // C2107 }; #pragma pop_macro("new") //---------------------------------------------------------------------
Die Compilermeldung dazu:
error C2676: binary '[' : 'System::Data::DataTableCollection __gc *' does not define this operator or a conversion to a type acceptable to the predefined operator
error C2107: illegal index, indirection not allowed
das es irgendwie ein falscher index ist mit dem ich zugreife, ist mir doch die fehlermeldungen ja auch klar...nur greife ich halt auf genau die gleiche art und weise zu, wie auch im oben stehenden (managed code, funktioniert fehlerfrei!) beispiel, das meiner arbeit zu grunde liegt...
@jochen: genau darum geht die thematik ja. ich möchte eine unmanaged klasse schreiben, in der ich aber an diversen zeilen managed code benutzen muss. eben dafür ist das kit gcroot da.
-
Hm, ich bin zu oberflächlich. (Allerdings ist es auch ein wenig fies die zwei Zeilen unter den vielen Kommentaren so zu markieren ;o)
Du kannst gcroot einsetzen, aber da muss es auch ^ sein und nicht * !
gcroot<OleDbConnection^> oConn; oConn = gcnew OleDbConnection(S"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"./kfz.mdb\"");
Setze das mal um und schau was die Fehlermeldungen dann sagen. (Vorrausgesetzt der zweite Teil wird auch mit VS 2005 übersetzt).
-
KaneMX schrieb:
@jochen: genau darum geht die thematik ja. ich möchte eine unmanaged klasse schreiben, in der ich aber an diversen zeilen managed code benutzen muss. eben dafür ist das kit gcroot da.
Und was hat das damit zu tun, dass Du "managed C++" und "C++/CLI" durcheinander bringst?
Also
gcroot<DataTable*> oDataTable;
(Managed C++; böse, böse, ... nicht mehr verwenden!)
=>gcroot<DataTable^> oDataTable;
(C++/CLI gute gute...)
-
error C3191: '^' : incompatible with '/clr:oldSyntax' command line option
bekomme ich wenn ich versuche was du gesagt hast
aber in dem artikel auf den ich mich bezog (http://www.codeproject.com/managedcpp/adonetinmfc.asp?df=100&forumid=16454&exp=0&select=1566682) wurde es ja auch mit dem * operator gemacht.
-
Nimm das oldSyntax mal raus und bau es auf die neue Syntax um. Machst Dir das leben damit wirklich leichter.
Der Aritkel wird etwas älter sein. Im VS2003 gab es C++/CLI nicht. Jetzt wo es da ist wirst Du Dir das leben erleichtern.
(Der eigentliche Fehler ist damit vermutlich nicht behoben, aber die Arbeit lohnt sich auf jedenfall, zumal man hier leichter helfen kann. C++/CLI sitzt einfach besser
-
jap du hast recht, habe auf normal CLI umgestellt und alle * durch ^ ersetzt, jetzt funktioniert es soweit jedenfalls fehlerfrei.
danke vielmals
-
Und warum compilierst Du mit "/clr:oldsyntax"? Würde ich dringend davon abraten.
Aber mit "oldsyntax" stimmt natürlich das "*"...Also bei mir compiliert folgendes Beispiel problemlos (/clr):
#include <vcclr.h> int main(array<System::String ^> ^args) { System::Data::DataSet ^ds; System::Data::DataTable ^dt = ds->Tables[0]; gcroot<System::Data::DataTable^> dtgc; dtgc = ds->Tables[0]; }
und folgendes auch mit "/clr:oldSyntax":
#include <vcclr.h> int main() { System::Data::DataSet *ds; System::Data::DataTable *dt = ds->Tables->get_Item(0); gcroot<System::Data::DataTable*> dtgc; dtgc = ds->Tables->get_Item(0); }
(managed C++ kennt keine BuildIn-Indexer!)
-
(managed C++ kennt keine BuildIn-Indexer!)
Ah... verdammmt. Stimmt. Das war ja der murks mit ->default
-
Allerdings kennt er weder die Bezeichner IEnumerator noch ArrayList, was das Arbeiten mit OLE extrem erschwert.
Woran liegt das?
-
Hast Du die Namensräume bekannt gemacht ?
System::Collections::ArrayList
System::Collections::Generic::IEnummerator
-
KaneMX schrieb:
Allerdings kennt er weder die Bezeichner IEnumerator noch ArrayList
!???
Vielleicht an dem fehlendenusing namespace System::Collections;
!?
-
ok ich gebe zu, die frage war dumm und unnötig
natürlich funzt es jetzt, danke nochmal
-
leider gibt es wieder ein weiteres Problem, offensichtlich wieder mit einem index, wieder C2676:
while(oEn->MoveNext()) { oRow = dynamic_cast<DataRow^>(oEn->Current); nID = System::Convert::ToInt32(oRow["id"]); // C2676 nBaujahr = System::Convert::ToInt32(oRow["baujahr"]); // C2676 nLeistung = System::Convert::ToInt32(oRow["leistung"]); // C2676 };
1>.\cdb.cpp(71) : error C2676: binary '[' : 'gcroot<T>' does not define this operator or a conversion to a type acceptable to the predefined operator
1> with
1> [
1> T=System::Data::DataRow ^
1> ]
-
Was ist denn "oRow"?
System::Data::DataRow ^dr; int i = System::Convert::ToInt32(dr["a"]);
geht bei mir Problemlos...
-
PS: Warum verwendest Du den gcroot an stellen, wo es gar nicht nötig ist?
gcroot wird *nur* benötigt, wenn Du ein managed Object in einer Klasse als *Member-Variable* ablegen willst!!! Innerhalb einer Methode kannst Du auch in einer "non-gc" Klasse direkt mit ^ arbeiten!