www.mikrocontroller.net

Forum: PC-Programmierung Eigenes Borland Builder C++ Programm stürzt ab


Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht muss ich "Tcan CAN;" einfach ganz am Anfang in die lpt.cpp
Datei reinschreiben.

Kann mir dazu jemand helfen?

Autor: Jonny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo....

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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.

Autor: AndreasH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: AndreasH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.