Hallo! Ich bin gerade dabei mit Baorland Builder C++ 5.0 eine Oberfläche für einen CAN Adapter zu bauen. Ich habe zwei Units (lpt.cpp und can.cpp) In der Unit can.cpp habe ich alle notwendigen Routinen reingestellt. Zum Ansteueren der LPT benutze ich die inpou32.dll Datei. In der Unit can.cpp habe ich funktionen geschrieben, mit denen ich die DLL lade bzw. wieder schließen kann. z.B.: -->can.cpp class Tcan { void Tcan::LoadLIB(void) { /* Load the library */ hLib = LoadLibrary("inpout32.dll"); if (hLib == NULL) { ShowMessage("LoadLibrary Failed.\n"); } /* get the address of the function */ inp32 = (inpfuncPtr) GetProcAddress(hLib, "Inp32"); if (inp32 == NULL) { ShowMessage("GetProcAddress for Inp32 Failed.\n"); } oup32 = (oupfuncPtr) GetProcAddress(hLib, "Out32"); if (oup32 == NULL) { ShowMessage("GetProcAddress for Oup32 Failed.\n"); } } } -->can.h class Tcan { private: public: typedef short _stdcall (*inpfuncPtr)(short portaddr); typedef void _stdcall (*oupfuncPtr)(short portaddr, short datum); HINSTANCE hLib; inpfuncPtr inp32; oupfuncPtr oup32; void Tcan::LoadLIB(void); } Diese Funktion rufe ich dann in der anderen Unit auf (lpt.cpp) #include "can.h" void start(void) { Tcan * CAN = new Tcan; Tcan->LoadLib(); } Wenn diese Funktion dann ausführe, stürtz mein Programm total ab. Adressverletzung! Was mache ich da Falsch? Ich denke da Problem liegt bei der Funktion start(). Wie kann ich diesen Ausdruck "Tcan * CAN = new Tcan;" global machen, so dass ich nur einmal dies aufrufen muss?
Das ist so falsch und der Compiler sollte sich eigentlich weigern, das zu übersetzen: Tcan * CAN = new Tcan; Tcan->LoadLib(); Besser wäre CAN->LoadLib(); Im übrigen: Lass' Dein Programm im Debugger laufen, dann solltest Du eigentlich herausfinden können, was schief geht. Außerdem solltest Du in Deiner Funktion LoadLib nicht nur eine Fehlermeldung ausgeben und dann weitermachen, sondern die Funktion sinnvoll beenden: hLib = LoadLibrary("inpout32.dll"); if (hLib == NULL) { ShowMessage("LoadLibrary Failed.\n"); } inp32 = (inpfuncPtr) GetProcAddress(hLib, "Inp32"); Überleg' mal, was hier passiert, wenn hLib NULL ist.
Ok ich habs kappiert! So wie hier "CAN->LoadLib();" kann ich die Funktion nicht starten. Mein Programm braucht dann immer diesen Audruck "Tcan * CAN = new Tcan;". Wie kann ich dies Global machen, so dass ich diesen Ausdruck nicht immer schreiben muss?
Oumann ich hab Mist erzählt. Ich muss mich korrigieren. Stimmt ich muss CAN->LoadLib(); schreiben. Ok aber dieser Ausdruck "Tcan * CAN = new Tcan;" möchte ich Global setzen. Ich will nicht ständig diesen Ausruck schreiben. Wie geht das?
Na, außerhalb Deines Funktionsrumpfes einfach hinschreiben Tcan CAN; Dann aber bei Zugriffen auf CAN keine Pointerdereferenzierung mehr durchführen, also anstelle von CAN->LoadLib(); musst Du CAN.LoadLib(); hinschreiben.
Vielen Dank! Ich werde das mal ausprobieren. Und wie sieht es aus wenn ich die Funktion verlasse bzw. Programm schließe, da muss dich der Speicher dann wieder freigegeben werden --> delete. Wo muss ich das dann ausführen?
Du musst bei dieser Art der Variablendeklaration Dich weder um das Anlegen mit new noch um das Löschen mit delete kümmern, das macht der Compiler schon für Dich. Allerdings solltest Du berücksichtigen, daß der Konstruktor der Variablen aufgerufen wird, bevor main() aufgerufen wird - also nicht im Konstruktor irgendwelche Initialisierungen erwarten, die erst in main() durchgeführt werden.
Hallo RUFUS! Ich habe mal deinen Vorschlag in mein Programm eingebracht. Leider funktioniert dies nicht. Wenn ich "Tcan CAN;" in die Header von der Unit "lpt.h" einfüge, dann erscheint vom Borland Builder diese Meldung "Typenname erwartet. Hmm...was kann das sein?
Vielleicht muss ich "Tcan CAN;" einfach ganz am Anfang in die lpt.cpp Datei reinschreiben. Kann mir dazu jemand helfen?
"Wenn ich "Tcan CAN;" in die Header von der Unit "lpt.h" einfüge," Was ist denn das für ein Quark? Das gehört nicht in eine Headerdatei, sondern in eine C/CPP-Datei. "Unit" ist als Begriff hier völlig fehl am Platze.
Hallo, ich meine Du musst TCan* Can; am Anfang Deiner CPP-Unit einfügen. Damit ist es lokal und nicht global. Du kannst das auch in die Header-Datei machen. Das hat aber den Nachteil, wenn Du die Header-Datei in anderen Units einbindest, meckert es der Compiler als mehrfach deklariert an. Irgendwo im Programm kommt dann: void start(void) { CAN = new Tcan; Tcan->LoadLib(); } Und das: if (hLib == NULL) { ShowMessage("LoadLibrary Failed.\n"); } solltest Du wirklich noch einmal überdenken. Zum testen einfach mal die dll löschen. Spätestens dann merkst Du was Rufus meinte. Wenn er es Dir direkt gesagt hätte, wäre der Lerneffekt flöten gegangen :) Grüße Andreas
Nein, darum geht es nicht. Jonny möchte sein Objekt nutzen können, ohne new/delete verwenden zu müssen. Daher darf eben kein Pointer verwendet werden, sondern es muss eine globale Variable verwendet werden. Beispiel: /* bla.h */ extern TCan CAN; /* ende von bla.h */ /* bla.cpp */ // übliche #include-Orgie #include "can.h" // irgendwo muss ja der Datentyp TCan definiert werden #include "bla.h" TCan CAN; int main() { CAN.LoadLib(); // etc. etc. } /* ende von bla.cpp */ Auf bla.h kann verzichtet werden, wenn es nur ein Sourcemodul gibt, das auf die Variable CAN zugreifen soll - sonst ist bla.h in jedes Sourcemodul einzubinden, das diese Variable verwendet. Da LoadLib() durchaus fehlschlagen kann, ist hier eine sinnvolle Fehlerbehandlung angesagt - so könnte beispielsweise LoadLib einen Rückgabewert erhalten, der aussagt, ob's geklappt hat ... Mit "units" hat all' das übrigens immer noch nichts zu tun.
"Jonny möchte sein Objekt nutzen können, ohne new/delete verwenden zu müssen." Wo steht das? Ich habe das so verstanden, dass er die Variable CAN überall benutzen will. Egal ob als Pointer oder direkt die Klasse. Dafür muss in der Can.cpp stehen: TCan* Can; in der Can.h muss stehen: extern TCan* Can; Die Can.h muss dann in der lpt.c includiert werden. Wenn dass extern jetzt weggelassen wird und ebenso das TCan* Can in der Can.cpp dann würde der Compiler dass als doppelte Deklaration anmeckern. Insofern hat das schon was mit units zu tun. Im C++-Builder wird jede zum Projekt zugehörige Datei unit genannt. @Rufus T. Firefly: Oder was meintest Du mit units? Wichtig ist das vor dem Zugriff in der lpt.cpp die Variable Can initialisiert wurde. Sonst gibts einen Speicherfehler. Also irgendwo "Tcan * CAN = new Tcan;" vorher. Das darf auch nur einmal erfolgen. Insofern darf er das gar nicht mehrfach durchführen. Zur Sicherheit kann er aber auch noch folgendes machen: if (Can != NULL) Can->LoadLib(); else ShowMessage("Wir haben ein Problem"); Das "Tcan->LoadLib();" war übrigens Quatsch was ich da geschrieben habe, so muss es sein: "Can->LoadLib()"; Grüße Andreas
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.