Fehler mit GetComponentByName



  • Hi,
    ich lese zur Zeit das Buch "Spieleprogrammierung mit DirectX und C++".

    Mein Problem ist folgendes Beispiel:

    # include <stdio.h>
    # include <windows.h>
    # include <commctrl.h>
    # include "resource.h"
    # include "ClientServer.h"
    # include "DXUtil.h"
    
    HINSTANCE meine_instanz = 0;
    HWND mein_serverdialog = 0;
    
    //# define BUILD "Duell-Server (" __DATE__ ", " __TIME__ ")"
    # define BUILD "Duell-Server"
    # pragma message("Build: " BUILD)
    
    // V03 Beginn
    
    # define ANGEHALTEN		0
    # define GESTARTET		1
    # define SPIELBEREIT    2
    # define SPIEL_LAEUFT   3
    
    class duell_server
    	{
    	public:
    		CRITICAL_SECTION critsec;
    		int status;
    		char hostname[64];
    		char sessionname[64];
    		DWORD portnummer;
    		int maxspieler;
    		IDirectPlay8Server *server;
    
    		duell_server();
    		~duell_server();
    
    		void lock() { EnterCriticalSection( &critsec);}
    		void unlock() { LeaveCriticalSection( &critsec);}
    
    		int start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp);
    		void stop();
    	};
    
    duell_server::duell_server()
    	{
        CoInitializeEx( NULL, COINIT_MULTITHREADED);
        InitializeCriticalSection( &critsec);
    
    	server = 0;
    	hostname[0] = 0;
    	maxspieler = 4;
    	strcpy( sessionname, "Duell");
    	portnummer = 4711;
    	status = ANGEHALTEN;
    	}
    
    duell_server::~duell_server()
    	{
        DeleteCriticalSection( &critsec);
        CoUninitialize();
    	}
    
    int duell_server::start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp)
    	{
        HRESULT hr;
        PDIRECTPLAY8ADDRESS adr = 0;
        DPN_APPLICATION_DESC adsc;
    	WCHAR buf[64];
    	DWORD buflen = 64;
    	DWORD anza = 1;
    	DWORD type;
    
    	strcpy( sessionname, sname);
    	portnummer = pno;
    	maxspieler = maxsp;
    
    	hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER,
                                           IID_IDirectPlay8Server, (LPVOID*) &server);
    	if( hr < 0)
    		goto RETURN;
    	hr = server->Initialize( 0, msghandler, 0);
    	if( hr < 0)
    		goto RETURN;;
    	hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
    						   CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, 
    						   (LPVOID*)&adr );
    	if( hr < 0)
    		goto RETURN;
    	hr = adr->SetSP( &CLSID_DP8SP_TCPIP);
    	if( hr < 0)
    		goto RETURN;
    	adr->AddComponent( DPNA_KEY_PORT, &portnummer, sizeof(portnummer), DPNA_DATATYPE_DWORD);
    	DXUtil_ConvertGenericStringToWide( buf, sessionname);
    	ZeroMemory( &adsc, sizeof(DPN_APPLICATION_DESC));
    	adsc.dwSize = sizeof( DPN_APPLICATION_DESC);
    	adsc.dwFlags = DPNSESSION_CLIENT_SERVER;
    	adsc.guidApplication = my_guid;
    	adsc.pwszSessionName = buf;
    	adsc.dwMaxPlayers = maxspieler + 1;
    	hr = server->Host( &adsc, &adr, 1, NULL, NULL, (void *)-1, 0);
    	if( hr < 0)
    		goto RETURN;
    	server->GetLocalHostAddresses(&adr, &anza, 0);
    	[b]adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type);[/b]
    	DXUtil_ConvertWideStringToAnsi( hostname, buf, 64);
    
    	RETURN:
    	if( adr)
    		adr->Release();
    	return hr;
    	}
    
    void duell_server::stop()
    	{
        if( server)
    		{
            server->Close( 0);
            server->Release();
    		server = 0;
    		}
    	status = ANGEHALTEN;
    	}
    
    duell_server mein_server;
    
    // V03 Ende
    
    void spielerliste_initialisieren( HWND hDlg)
    	{
    	HWND lst;
    	LVCOLUMN lvc;
    
    	lst = GetDlgItem(hDlg, IDC_SPIELERLISTE);
    	ListView_SetExtendedListViewStyleEx( lst, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
    	lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
    	lvc.fmt = LVCFMT_LEFT;
    	lvc.cx = 36;
    	lvc.pszText = "Nr";
    	ListView_InsertColumn( lst, 0, &lvc);
    	lvc.cx = 96;
    	lvc.pszText = "Name";
    	ListView_InsertColumn( lst, 1, &lvc);
    	lvc.fmt = LVCFMT_RIGHT;
    	lvc.cx = 96;
    	lvc.pszText = "Joystick X";
    	ListView_InsertColumn( lst, 2, &lvc);
    	lvc.cx = 96;
    	lvc.pszText = "Joystick Z";
    	ListView_InsertColumn( lst, 3, &lvc);
    	}
    
    void chatliste_initialisieren( HWND hDlg)
    	{
    	HWND lst;
    	LVCOLUMN lvc;
    
    	lst = GetDlgItem(hDlg, IDC_CHATLISTE);
    	ListView_SetExtendedListViewStyleEx( lst, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
    	lvc.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
    	lvc.fmt = LVCFMT_LEFT;
    	lvc.cx = 120;
    	lvc.pszText = "Name";
    	ListView_InsertColumn( lst, 0, &lvc);
    	lvc.cx = 360;
    	lvc.pszText = "Text";
    	ListView_InsertColumn( lst, 1, &lvc);
    	}
    
    // V03 Beginn
    
    HRESULT WINAPI server_messagehandler( PVOID pvUserContext, DWORD dwMessageType, PVOID pMessage)
    	{
    	int ret = S_OK;
    
    	mein_server.lock();
    
        switch( dwMessageType)
    		{
    	case DPN_MSGID_ENUM_HOSTS_QUERY:
    //		ret = !S_OK; // Test: Query abweisen
    		break;
    		}
    
    	mein_server.unlock();
    
        return ret;
    	}
    
    void next_serverstate( HWND hDlg)
    	{
    	char sessionname[64];
    	int portnummer;
    	int maxsp;
    	int hr;
    
    	switch( mein_server.status)
    		{
    	case ANGEHALTEN:
    		SetCursor( LoadCursor(NULL, IDC_WAIT));
    		GetDlgItemText( hDlg, IDC_SESSION_NAME, sessionname, 64);
    		portnummer = GetDlgItemInt( hDlg, IDC_PORT, 0, FALSE);
    		maxsp = GetDlgItemInt( hDlg, IDC_MAXSPIELER, 0, 0);
    		if( maxsp < 2)
    			maxsp = 2;
    		if( maxsp > MAX_PLAYERS)
    			maxsp = MAX_PLAYERS;
    		SetDlgItemInt( hDlg, IDC_MAXSPIELER, maxsp, FALSE );
    		hr = mein_server.start( server_messagehandler, sessionname, portnummer, maxsp);
    		if( hr == S_OK)
    			{
    			SetDlgItemText( hDlg, IDC_IP_ADRESSE, mein_server.hostname);
    			mein_server.status = GESTARTET;
    			}
    		else
    			{
    			MessageBox( hDlg, DXGetErrorDescription9( hr), "Duell-Meldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
    			mein_server.stop();
    			}
    		SetCursor( LoadCursor(NULL, IDC_ARROW));
    		break;
    		}
    	}
    
    void display_serverstate( HWND hDlg)
    	{
    	int st;
    
    	switch( mein_server.status)
    		{
    	case ANGEHALTEN:
            SetDlgItemText( hDlg, IDC_STATUS, "Server angehalten");
    		SetDlgItemText( hDlg, IDC_START, "Server starten");
            SetDlgItemText( hDlg, IDC_SESSION_NAME, mein_server.sessionname);
            SetDlgItemInt( hDlg, IDC_PORT, mein_server.portnummer, FALSE );
            SetDlgItemInt( hDlg, IDC_MAXSPIELER, mein_server.maxspieler, FALSE );
    		break;
    	case GESTARTET:
    		SetDlgItemText( hDlg, IDC_STATUS, "Server läuft");
            SetDlgItemText( hDlg, IDC_START, "Spiel laden");
    		break;
    		}
    	st = (mein_server.status == ANGEHALTEN);
    	EnableWindow( GetDlgItem(hDlg, IDC_SESSION_NAME), st);
    	EnableWindow( GetDlgItem(hDlg, IDC_PORT), st);
    	EnableWindow( GetDlgItem(hDlg, IDC_MAXSPIELER), st);
    	}
    
    // V03 Ende
    
    INT_PTR CALLBACK serverdialog( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
    	{
    	HICON hIcon;
    
        switch( msg ) 
    		{
        case WM_INITDIALOG:
    		SetWindowText( hDlg, BUILD);
    		hIcon = LoadIcon( meine_instanz, MAKEINTRESOURCE( IDI_MAIN));
    		SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
    		SendMessage( hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
    		spielerliste_initialisieren( hDlg);
    		chatliste_initialisieren( hDlg);
    // V03 Beginn
    		display_serverstate( hDlg);
    // V03 Ende
    		mein_serverdialog = hDlg;
            return TRUE;
        case WM_COMMAND:
            switch( LOWORD(wParam))
    			{
    // V03 Beginn
            case IDC_START:
    			next_serverstate( hDlg);
    			display_serverstate( hDlg);
    			return TRUE;
    // V03 Ende
            case IDCANCEL:
    // V03 Beginn
    			SetCursor( LoadCursor(NULL, IDC_WAIT));
                mein_server.stop();
    			SetCursor( LoadCursor(NULL, IDC_ARROW));
    // V03 Ende
                EndDialog( hDlg, 0);
                return TRUE;
    			}
            break;
    		}
        return FALSE;
    	}
    
    INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, INT nCmdShow )
    	{
    	INITCOMMONCONTROLSEX ic;
    
    	ic.dwSize = sizeof( ic);
    	ic.dwICC = ICC_LISTVIEW_CLASSES;
    	InitCommonControlsEx( &ic);
    
    	meine_instanz = hInst;
    
        DialogBox( hInst, MAKEINTRESOURCE(IDD_SERVER), NULL, (DLGPROC)serverdialog);
    
        return 1;
    	}
    

    Übersetzen lässt sich alles. Allerdings stürzt das Programm in duell_server::start() ab. Der Debugger meldet bei adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type); folgendes:

    Eine Ausnahme (erste Chance) bei 0x004012f0 in Server.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00000000.
    Unbehandelte Ausnahme bei 0x004012f0 in Server.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00000000.
    Das Programm "[1556] Server.exe: Systemeigen" wurde mit Code 0 (0x0) beendet.
    

    Kann mir jemand sagen, wie ich diesen Fehler beheben kann??
    Danke für jede Hilfe
    Ghill



  • wer soll denn das alles lesen?
    reduzier doch mal deinen Code auf die wesentlichen Zeilen, also dort wo es vermutlich kracht. und mit den [/cpp] tags ist der c++-code dann auch lesbarer 😉

    /edit: "Zugriffsverletzung beim lesen an 0x000000..." klingt fuer mich nach Zugriffsversuch auf einen Null-Zeiger...



  • ok, hier nochmal nur die funktion:

    int duell_server::start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp)
        {
        HRESULT hr;
        PDIRECTPLAY8ADDRESS adr = 0;
        DPN_APPLICATION_DESC adsc;
        WCHAR buf[64];
        DWORD buflen = 64;
        DWORD anza = 1;
        DWORD type;
    
        strcpy( sessionname, sname);
        portnummer = pno;
        maxspieler = maxsp;
    
        hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER,
                                           IID_IDirectPlay8Server, (LPVOID*) &server);
        if( hr < 0)
            goto RETURN;
        hr = server->Initialize( 0, msghandler, 0);
        if( hr < 0)
            goto RETURN;;
        hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
                               CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address,
                               (LPVOID*)&adr );
        if( hr < 0)
            goto RETURN;
        hr = adr->SetSP( &CLSID_DP8SP_TCPIP);
        if( hr < 0)
            goto RETURN;
        adr->AddComponent( DPNA_KEY_PORT, &portnummer, sizeof(portnummer), DPNA_DATATYPE_DWORD);
        DXUtil_ConvertGenericStringToWide( buf, sessionname);
        ZeroMemory( &adsc, sizeof(DPN_APPLICATION_DESC));
        adsc.dwSize = sizeof( DPN_APPLICATION_DESC);
        adsc.dwFlags = DPNSESSION_CLIENT_SERVER;
        adsc.guidApplication = my_guid;
        adsc.pwszSessionName = buf;
        adsc.dwMaxPlayers = maxspieler + 1;
        hr = server->Host( &adsc, &adr, 1, NULL, NULL, (void *)-1, 0);
        if( hr < 0)
            goto RETURN;
        server->GetLocalHostAddresses(&adr, &anza, 0);
        adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type);
        DXUtil_ConvertWideStringToAnsi( hostname, buf, 64);
    
        RETURN:
        if( adr)
            adr->Release();
        return hr;
        }
    


  • Bist du mal mit einem Debugger Schritt fuer Schritt da durchmaschiert und kannst uns sagen an welcher Stelle er abschmiert? Viele der Variablennamen kommen so vom Himmel, da kann niemand genau wissen, welche davon wo und wie initialisiert wurden...



  • er kommt eben bis adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type);.

    zu den unbekannten variablen mla noch die klasse:

    class duell_server
    	{
    	public:
    		CRITICAL_SECTION critsec;
    		int status;
    		char hostname[64];
    		char sessionname[64];
    		DWORD portnummer;
    		int maxspieler;
    		IDirectPlay8Server *server;
    
    		duell_server();
    		~duell_server();
    
    		void lock() { EnterCriticalSection( &critsec);}
    		void unlock() { LeaveCriticalSection( &critsec);}
    
    		int start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp);
    		void stop();
    	};
    

    Die guid my_guid steht in ner header datei.

    des sollten dann alle variablen in der funktion sein.



  • Hi,

    ich kenne zwar die API nicht, aber 2 Tipps habe ich doch:
    1.) Bei Funktionen, die "Pointer setzen" (wo Du also einen Pointer als return erhältst oder einen (nonconst) Pointer/Referenz auf einen Pointer als Parameter übergibst, solltest Du anschließend prüfen, ob der Pointer nicht 0 ist; nicht wenige APIs geben im Fehlerfall einen 0-Pointer zurück.

    2.) "goto = BÄH" 😉
    Für sowas ist throw der bessere Kandidat. Entweder lässt Du die exception "durchfliegen" (damit ersparst Du dem Aufrufer ebenfalls if-goto-Orgien) oder Du fängst sie eben und wandelst sie in einen entsprechenden Returncode um. Für das Aufräumen kannst Du entsprechende "scopeguards" einsetzen.
    Ich würde eher schreiben:

    #include <stdexcept>
    using std::runtime_error:
    
    int duell_server::start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp)    {
    // ...
       struct adr_guard {
          PDIRECTPLAY8ADDRESS& guarded_adr;
          adr_guard(PDIRECTPLAY8ADDRESS& a) : guarded_adr(a) { }
          ~adr_guard(if( adr) adr->Release();}
       };
       adr_guard AG(adr);      
    
       if((0 > (hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Server, (LPVOID*) &server))) ||
           (0 > (hr = server->Initialize( 0, msghandler, 0))) ||
           (0 > (hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&adr ))) ||
           (0 > (hr = adr->SetSP( &CLSID_DP8SP_TCPIP)))) {
          throw runtime_error("hr < 0");
       }
    
        adr->AddComponent( DPNA_KEY_PORT, &portnummer, sizeof(portnummer), DPNA_DATATYPE_DWORD);
        DXUtil_ConvertGenericStringToWide( buf, sessionname);
        ZeroMemory( &adsc, sizeof(DPN_APPLICATION_DESC));
        adsc.dwSize = sizeof( DPN_APPLICATION_DESC);
        adsc.dwFlags = DPNSESSION_CLIENT_SERVER;
        adsc.guidApplication = my_guid;
        adsc.pwszSessionName = buf;
        adsc.dwMaxPlayers = maxspieler + 1;
        if(0 > (hr = server->Host( &adsc, &adr, 1, NULL, NULL, (void *)-1, 0))) throw runtime_error("hr < 0");
        server->GetLocalHostAddresses(&adr, &anza, 0);
        adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type);
        DXUtil_ConvertWideStringToAnsi( hostname, buf, 64);
    
        return hr;
    

    Im Prinzip braucht start() dann gar keinen Returnwert mehr, weil es immer geklappt hat, wenn keine exception fliegt.
    Wenn man es genauer haben möchte, kann man natürlich auch das "Mehrfach-if" oben aufdröseln und für jeden Funktionsaufruf einen eigenen Exceptiontext schreiben.
    Vielleicht ist es auch noch sinnvoller, eine eigene Exceptionklasse bereitzustellen:

    #include <stdexcept>
    using std::runtime_error:
    
    struct duell_server_Except : public runtime_error {
       int error;
       duell_server_Except(int r, string const& t) : runtime_error(t), error(r) {}
       char const* what() const throw() { 
          ostringstream ost; 
          ost << runtime_error::what() << "; error: " << error;
          return ost.str().c_str();
       }
    };
    
    void duell_server::start( PFNDPNMESSAGEHANDLER msghandler, char *sname, int pno, int maxsp)    {
    // ...
    
       if(0 > (hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Server, (LPVOID*) &server)))
          throw duell_server_Except(hr, "CoCreateInstance 1");
       if(0 > (hr = server->Initialize( 0, msghandler, 0)))
          throw duell_server_Except(hr, "server->Initialize");
       if(0 > (hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*)&adr )))
          throw duell_server_Except(hr, "CoCreateInstance 2");
       if(0 > (hr = adr->SetSP( &CLSID_DP8SP_TCPIP))) 
          throw duell_server_Except(hr, "adr->SetSP");
    
    // ...
    
        if(0 > (hr = server->Host( &adsc, &adr, 1, NULL, NULL, (void *)-1, 0)))
            throw duell_server_Except(hr, "server->Host");
        server->GetLocalHostAddresses(&adr, &anza, 0);
        adr->GetComponentByName( DPNA_KEY_HOSTNAME, buf, &buflen, &type);
        DXUtil_ConvertWideStringToAnsi( hostname, buf, 64);
    
    }
    

    Damit hast Du mehr Information (nicht nur hr, sondern auch die Position, wo der Fehler aufgetreten ist) als in Deiner Variante.

    Ist aber natürlich nur ein Vorschlag...

    Gruß,

    Simon2.



  • also, mittlerweile weis ich, dass das fehler bei

    hr = server->GetLocalHostAddresses(&adr, &anza, 0);
    

    entsteht.
    Mit

    DXGetErrorDescription9( hr)
    

    erhalte ich

    "Buffer too small".
    

    Was kann ich dagegen unternehmen. Auf nem anderen PC läuft das Programm übrigens....



  • Ghill schrieb:

    also, mittlerweile weis ich, dass das fehler bei

    hr = server->GetLocalHostAddresses(&adr, &anza, 0);
    

    entsteht.
    Mit

    DXGetErrorDescription9( hr)
    

    erhalte ich

    "Buffer too small".
    

    Was kann ich dagegen unternehmen. Auf nem anderen PC läuft das Programm übrigens....

    Ähh - das weist doch wohl darauf hin, dass der Buffer zu klein ist, oder ?
    Ich weiß nicht, welchen Buffer er da meint (das dürfte aber die Doku klären) ... ich vermute aber, dass anza mit 1 ein wenig zu klein geraten ist. Kann natürlich sein, dass auf dem anderen PC 1 reicht, weil es dort weniger "LocalHostAddresses" gibt...

    Gruß,

    Simon2.



  • du hast recht, anza muss entsprechend hochgesezt werden.... laut doku wird anza bei misserfolg auf die erforderliche zahl gesezt. ich werds gleich mal versuchen, danke für deine hilfe


Anmelden zum Antworten