Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

02.09.2008, 13:43

Nullpointer-Problem mit DirectPlay

Hi Forum!
Ich bin gerade an einem neuen Spiel, das man im Mehrspielermodus spielen soll. Da die Grundsteine gelegt sind hab ich mit dem Mehrspielerteil begonnen. Leider gibts schon beim Server ein kleines Problem:

Ich hab zwei Funktionen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
BOOL CServer::Init()
{
  Shutdown();

  // Create the Server object

  if(FAILED(CoCreateInstance(CLSID_DirectPlay8Server, NULL,    \
                             CLSCTX_INPROC,                    \
                             IID_IDirectPlay8Server,           \
                             (void**)&m_pDPServer)))
    return FALSE;

  return TRUE;
}


und

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int CServer::Host(GUID *guidAdapter, long Port, char *SessionName, char *Password, long MaxPlayers)
{
  DPN_APPLICATION_DESC dpad;
  IDirectPlay8Address *pDPAddress;
  WCHAR wSessionName[MAX_PATH], wPassword[MAX_PATH];

  // Disconnect from current connection

  Disconnect();

  // Error checking

  if(m_pDPServer == NULL)
    return -1;
  if(SessionName == NULL)
    return -2;

  // Get port selection

  if(!(m_Port = Port))
    return -3;

  // Initialize the Server object

  if(FAILED(m_pDPServer->Initialize((PVOID)this, NetworkMessageHandler, 0)))
    return -4;

// Hier kommt noch mehr, ist aber jetzt mal unwichtig


Jetzt hab ich noch ne Klasse CApp welche ne Instanz von der CServer-Klasse enthält:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
class CApp
{
private:
    CServer m_Server;
public:
CServer GetServer() {return m_Server;}
//...hier kommt noch mehr; unwichtig

};


Nun erstell ich ne Instanz der CApp-Klasse und ruf damit die beiden zuerst genannten Funktionen auf:

C-/C++-Quelltext

1
2
3
4
5
CApp *g_Application;
g_Application = new CApp;

g_Application->GetServer().Init();
g_Application->GetServer().Host(Adapter.GetGUID(0), 77777, "mysessionname");


Die Parameter bei der Host-Funktion sind jetzt auch noch unwichtig, denn:
Die Init()-Funktion liefert TRUE zurück, was mich schonmal freut. Die Host()-Funktion liefert -1 zurück, funktioniert also nicht. Wenn man in die Host()-Funktion schaut, sieht man, dass sie -1 zurückliefert, wenn m_pDPServer = null. Woran könnte das liegen?
(m_pDPServer ist übrigens ein Member von CServer vom Typ IDirectPlay8Server*)

Ich denk mal, dass die Init()-Funktion irgendetwas falsch macht, oder fehlt dort vielleicht noch irgendwas? Ich arbeite gerade das erste Mal mit DirectPlay...

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

2

02.09.2008, 21:39

Zitat

Woran könnte das liegen?

Das irgendjemand den Wert auf 0 gesetzt hat, oder er nie etwas anderes als 0 hatte?
Geh halt mal mit dem Debugger da Schritt für Schritt durch und behalte die Variable im Auge und irgendwann nimmt sie den Wert 0 an und dann kannst du den Fehler zurückverfolgen.

btw:
Bei solchen Klassen eignet sich RAII ausgezeichnet, dann ist das ganze gerade um einiges sauberer, als mit Init und Shutdown Zeugs.

3

02.09.2008, 23:53

Ich hab gerade was versucht: Ich hab die Init() und Host()-Funktionen global gemacht und ne globale Instanz von IDirectPlay8Server* erstellt. Rufe ich die dann auf, dann geht alles wie es sein sollte.
Dann dachte ich mir, dass zwar die Init()-Funktion der Klasse beim Aufruf TRUE zurückgibt, allerdings muss da etwas nicht stimmen. Also hab ich nochmal geschaut, ob sie auch wirklich aufgerufen wird, indem ich dort mit einem Nullpointer rumgespielt hab. Programm stürzte wie erhofft ab. Aber was ich komisch fand. Wenn ich ne boolesche Variable hatte, die gleich beim Funktionsaufruf auf true stellte, und diese nach dem Aufruf abfragte, so kam dabei weder true noch false raus. Das fand ich ein bisschen (besser gesagt sehr) seltsam.

Zusammenfassung: Wenn ich alles global mache, dann funktioniert es, obwohl die Funktionen alle gleich sind.

Edit: Was ist RAII?

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

4

03.09.2008, 00:22

Zitat

Zusammenfassung: Wenn ich alles global mache, dann funktioniert es, obwohl die Funktionen alle gleich sind.

Fazit: Du hast das Problem wahrscheinlich immernoch, aber es funktioniert einfach zufälligerweise. ;)

RAII:
http://en.wikipedia.org/wiki/Resource_acquisition_is_initialization

Sehr nützlich für alles, was mit Ressourcen zu tun hat, oder auch einfach, wenn man wo wieder was freigeben muss.

EDIT:
Ohne nähere Angaben zu Funktionen, die die Variable verändern, kann ich jetzt auch nichts mehr dazu sagen. Wie gesagt schau einfach mal ab dort, wo die Variable gefüllt wird und richtig ist mal solange bis sie nicht mehr stimmt, respktive 0 ist.

5

03.09.2008, 00:41

Zitat

Ohne nähere Angaben zu Funktionen, die die Variable verändern, kann ich jetzt auch nichts mehr dazu sagen.

Die einzige Funktion ist die CServer::Init(). Was ich auch mal probieren könnte: Ich lass meine globale Init-Funktion nicht die globale Serverinstanz einrichten, sondern die der CServer-Klasse. Weil gerade verwende ich ja auch eine globale Serverinstanz. Nachdem ich dann die neue globale Init-Funktion aufrufe, rufe ich dann die CServer::Host() auf. Mal schauen ob das geht.

Zitat

RAII:
http://en.wikipedia.org/wiki/Resource_acquisition_is_initialization

Sehr nützlich für alles, was mit Ressourcen zu tun hat, oder auch einfach, wenn man wo wieder was freigeben muss.


Sieht mir gerade zu kompliziert aus und zu so später Stunde kann ichs jetzt nicht durchlesen. Schaus mir nacher wahrscheinlich nochmal an.

Zitat

Wie gesagt schau einfach mal ab dort, wo die Variable gefüllt wird und richtig ist mal solange bis sie nicht mehr stimmt, respktive 0 ist.


Da das Problem eindeutig (für mich zumindest) an der Init()-Funktion liegt, und die nicht viel macht, bringts das wohl nicht, obwohl ich echt schauen könnte ob die echt nichts verändert.
Noch ne Frage: Mit F10 geht der Debugger zum nächsten Schritt, aber das ist ja nicht die nächste Anweisung und dann wird manchmal was für mich wichtiges übersprungen. Kann ich irgendwie manuell Haltepunkte setzen? (verwende Visual Studio 2008)

Ich werd das alles dann mal nacher ausprobieren. Danke.

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

6

03.09.2008, 00:52

Also ich sehe da nirgends eine Benutztung, noch Initialisierung von m_pDPServer. Darum sage ich einfach mal bis du was anderes gezeigt hast, dass m_pDPServer nach der Initialisierung auf 0 oder ohne Initialisierung irgnedwas ungültiges ist.

RAII ist im Prinzip ganz einfach, aber auch sehr mächtig. Am besten du führst dir mal das C++ file Beispiel zu Gemüte. Das ist recht verständlich und zeigt um was das es geht.

EDIT:
Du kannst auch Schritt für Schritt durchgehen.
Und Haltepunkte setzen, indem du dort, wo die Zahlen stehen einfach reinklickst. Dann gibt es einen roten Punkt und dort hält der Debugger, wenn du ihn laufen lässt.
Und wenn er angehalten hat, kannst du auch in Funktionen reinspringen. (Dafür gibts dann eine Toolbox).

Werbeanzeige