CreateThread - keine Memberfunktion erlaubt ?



  • Hmmmm schrieb:

    Folgendes : Wenn ich die Methode statisch mache, dann kann ich mit ihr auch nur-noch auf anderes, statisches zugreifen, was sehr unpassend wäre.

    Könntest halt ein this übergeben, etwas hässlich, aber ich glaube nicht, dass es eine andere Möglichkeit gibt..

    Hmmmm schrieb:

    CRT ... irgendeine .NET-Framework Sache oder ? Benutze ich eigentlich nicht ;P

    Tja ehm.. hat eher was mit C Funktionen zu tun. Und die nutzt du vermutlich schon 😉
    http://msdn.microsoft.com/en-us/library/abx4dbyh(v=vs.80).aspx

    Hmmmm schrieb:

    Nur um nochmal sicher zu gehen : "Wenn überhaupt, dann ..." -> Eine normale Memberfunktion ist also nicht threadfähig ? Woran liegt das ?

    Ich glaube nicht, dass das mit einer normalen Memberfunktion geht.
    Aber das ist auch nicht umbedingt ein Anfängerthema. Siehe auch
    http://msdn.microsoft.com/en-us/library/ms686927(v=vs.85).aspx



  • Oh man, wie schlecht xD Aber bei den ganzen Abkürzungen behält man auch kein Überblick mehr ... CLI, MFC , ...

    Das mit dem this-pointer übergeben hat mir auch schon jemand gesagt, ich check aber nicht wie das helfen soll. Ich habe so gut wie noch nie static verwendet, also keine Ahnung ;P
    Ich mein dann hab ich innerhalb der Threadfunktion ne Klasseninstanz, kann ich dann normale Aufrufe machen oder wie ? Z.B : (MyClass*)param->MemberMethod(); obwohl das ne statische Funktion ist ?

    Und ja, Mutxen tu ich mir wohl lieber nicht an ;P Bzw dieses ganze Thread-Sicherheits blabla mit shared resourcen.



  • Hmmmm schrieb:

    dieses ganze Thread-Sicherheits blabla

    😉
    Wozu brauchst du denn überhaupt Threads? Die meisten Probleme lassen sich auch ohne Lösen.



  • Ja, die lassen sich über non-blocking Sockets vermeiden, fressen dafür dann aber viel mehr CPU.

    Ich schreibe an einem Chat-Programm, der Teil ist für den Client. Vllt würde es auch iwie mit Select gehen, hmmm. Aber .. nein. Denn einmal gibt es die Message-Schleife und einmal diese Schleife zum Empfangen von Daten. Die beiden müssen sich immer abwechseln von daher benutze ich Threads.

    Also c.a so :

    StartThread();
    
    while (GetMessage (&messages, NULL, 0, 0))
        {
    
            /* Translate virtual-key messages into character messages */
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
        }
    


  • cooky451 schrieb:

    Ich glaube nicht, dass das mit einer normalen Memberfunktion geht.

    Ne geht nicht. Eine Memberfunktion, die wie folgt deklariert ist:

    void myclass::funk();

    hat implizit immer einen Parameter, nämlich den Zeiger auf die aktuelle Instanz, sonst wüsste sie nicht, für welches aktuelle Objekt sie ausgeführt werden soll. Dementsprechend haben alle Memberfunktionen einen Parameter mehr, als man in der Deklaration angibt, und deshalb passt die Funktionssignatur nicht zur von der WINAPI verlangten Signatur.

    Eine statische Funktion hat diesen Zeiger nicht, sie kann auch ausgeführt werden, ohne das man ein Objekt erstellt, aber sie ist natürlich für alle Objekte dieser Klasse identisch.

    Um trotzdem verschiedene Objekte einer Threadklasse erstellen zu können, die unterschiedliche Funktionen ausführen, muss man wie folgt vorgehen:

    class threadClass
    {
        public:
            void startThread();
    
        protected:
            static void threadfunktion(LPVOID param);
            virtual void doSomething();
    };
    

    Die Funktion doSomething ist die eigentliche Threadfunktion, die in abgeleiteten Klassen definiert werden muss.
    Die Funktion startThread ruft CreateThread oder _beginthreadex auf und übergibt als Parameter (4. Parameter, wenn man CreateThread benutzt) einen Zeiger auf das aktuelle Objekt:

    void threadClass::startThread()
    {
        CreateThread(..., ..., threadClass::threadfunktion, this, ...
    }
    

    und als Threadfunktion die statische Funktion der Klasse. Diese wiederum ruft nun über den angelieferten Zeiger die 'richtige' Funktion auf:

    threadClass::threadfunktion(LPVOID param)
    {
        threadClass *ptr = reinterpret_cast<threadClass *> param;
        ptr->doSomething();
    }
    


  • Hmmmm schrieb:

    Ja, die lassen sich über non-blocking Sockets vermeiden, fressen dafür dann aber viel mehr CPU.

    Ich schreibe an einem Chat-Programm, der Teil ist für den Client. Vllt würde es auch iwie mit Select gehen, hmmm. Aber .. nein. Denn einmal gibt es die Message-Schleife und einmal diese Schleife zum Empfangen von Daten. Die beiden müssen sich immer abwechseln von daher benutze ich Threads.

    Nimm select .



  • Kann meinem Vorredner nur zustimmen. select ist eindeutig die bessere Variante. Gibt es einen Grund, warum du das nicht nutzen willst 😕



  • @ Belli Achso ! Ja, so macht das alles Sinn ;P Gut, ich denke das wäre mal dann die beste Lösung für mich, so werde ich es wohl machen 😉 Muss ich mir nurnoch überlegen, wie ich das alles wieder an meine Gui-Klasse weiter kriege. Sollte aber ein leichtes sein. Generell habe ich wenn ich Klassen benutzer aber dauernd das Problem, dass ich mir überlegen muss, wie Klasse A Daten an Klasse B weiter gibt, die diese braucht um zu funktionieren. Nervig 😕

    @ TyRoXx Nun ja, wie gesagt : Auch mit select() komme ich um Multithreading nicht rum. Zmnd wüsste ich nicht wie.



  • Wo ist das Problem mit select?

    Einfach
    PeekMessage + select und schon kannste den ganzen Thread Kram vergessen. Ist einfacher und eleganter. Was will man mehr? 😃



  • Hmmmm schrieb:

    @ TyRoXx Nun ja, wie gesagt : Auch mit select() komme ich um Multithreading nicht rum. Zmnd wüsste ich nicht wie.

    Tutorial



  • Achsoo, mit PeekMessage ist das natürlich kein Problem ;P Dann wird meine Klasse da ja ziemlich überflüssig. Werde das mal eben umsetzen.
    Auf jeden Fall : Danke an alle 😉 Das tut werd ich mir auch nochmal reinziehen, obwohl mir die Funktionsweise von select eigentlich klar ist. Naja, mehr oder weniger ;P
    Ich werd mich hier melden falls noch Probleme auftauchen.

    Schönen Abend wünsche ich noch !



  • Sooo, habe mal wieder ein Problem ;P
    Edit : Lustig, zum 3. mal hab ich hier beim Posten und kommentieren des Codes den fehler gefunden ;P Aber es bleibt ein Fehler :
    Ich habe bei jedem Clienten eine List-Box, die die Namen aller bisher Clients halten Soll. D.h wenn einer neuer Client auf den Server connected, muss dessen Namen bei jedem anderen Client zur Listbox hinzugefügt werden. Das ist im Prinzip so wie bei ICQ/MSN/Whatever die Kontaktliste.

    Hier erstmal der Server :

    #define MAX_CLIENTS 10
    
    // Ganzen Verbindungs-relevanten Sachen wie Socket erzeugen, SOCKADDR_IN füllen, binden, listn etc
    
    struct client_struct {
      SOCKET client;
      char name[254];
    };
    FD_SET fdSet;
    long rc = 0;
    char buf[1024];
    client_struct clients[MAX_CLIENTS];
    
    // Hier dann die eigentliche Select Schleife
    while(1) {
        // das Set leeren
        FD_ZERO(&fdSet);
        // "acceptSocket" ist das Socket zum Verbindungen annehmen
        FD_SET(acceptSocket,&fdSet); 
    
        // Alle bisher verbunden Clients erstmal in das set packen
        for(i=0;i<MAX_CLIENTS;i++) {
    
          if(clients[i].client!=INVALID_SOCKET) {
    
            FD_SET(clients[i].client,&fdSet);
          }
        }
    
        rc=select(0,&fdSet,NULL,NULL,NULL); 
        if(rc==SOCKET_ERROR) {
    
          cout << "Error: select failed, error code: " << WSAGetLastError() << endl;
    	  closesocket(acceptSocket);
    	  WSACleanup();
          return 1;
        }
    
        // Falls das Verbindunhs-Socket immernoch drin ist -> Verbindung annehmen
        if(FD_ISSET(acceptSocket,&fdSet)) {
          // Leeren Platz suchen
          for(i=0;i<MAX_CLIENTS;i++) {
    
            if(clients[i].client==INVALID_SOCKET) {
    
              clients[i].client=accept(acceptSocket,NULL,NULL);
              cout << "accepted a new client (" << i << ")" << endl;
              break;
            }
          }
        }
    
        // So, jetzt noch überprüfen ob irgendein anderes Socket was senden will 
        for(i=0;i<MAX_CLIENTS;i++) {
    
          if(clients[i].client==INVALID_SOCKET) {
            // cout << "Cannot use this client ... " << " i is : " << i << endl;
            continue; 
          }
    
          if(FD_ISSET(clients[i].client,&fdSet)) {
             // cout << "But this client works ! " << "i is : " << i << endl;
            rc = recv(clients[i].client,buf, sizeof(buf) ,0);
    
            // Falls recv 0 return oder eben SOCKET_ERROR dann hat der entsprechende Client die Verbindung gelöst
            if(rc==0 || rc==SOCKET_ERROR) {
    
              cout << clients[i].name << " pissed off, what a wanker ... " << endl;
    		  // Das möchte ich an dieser Stelle auch an alle anderen Clients weitergeben 
                      // Hier fehlt eigentlich noch das Un-Adden des Client von der Listbox, aber das mache ich später
    		  char temp[300];
    		  strncpy(temp, clients[i].name, sizeof(temp));
    		  strncat(temp, " pissed off, what a wanker ...\n", ( sizeof(temp) ) - strlen(temp) );
    		  for(int j = 0; j < MAX_CLIENTS; j++) {
    		  if(j != i && ( clients[j].client != INVALID_SOCKET ) )
    			  send(clients[j].client, temp , strlen(temp), 0 );
    		  }
              closesocket(clients[i].client); // Socket schlißen     
              clients[i].client=INVALID_SOCKET; // Platz im struct wieder frei geben
              memset( clients[i].name, 0, sizeof(clients[i].name) ); // Und den Namens-buffer auch leeren
            }
    
            else {
    
              buf[rc]='\0';
              cout << buf << endl; // Diese Ausgaben exisitieren beim Server immer zur Überprüfung
    
    		  // Ich habe hier art "special messages" erfunden, mit der Sachen wie Namen etc ausgetauscht werden
                      // Jeder Client schickt nach dem Connecten direkt diese special Message den Server, gefolgt von seinem Namen
                      // Daher der 2. recv call, ohne Überprüfung
    
    		  if(strcmp(buf, \r\r##SENDING CLIENT NAME##\r\r" ) == 0) {
    		     // cout << "Special message got send ! " << endl;
    		     rc = recv( clients[i].client, clients[i].name, sizeof( clients[i].name ) , 0); // Speicherung des gesendeten Namens im struct
    		     // cout << "Realised that there is a new client connected ... " << endl;
    		     clients[i].name[rc] = '\0';
    		     cout << clients[i].name << endl;
                         // Dashier ist eine 2. special-message, um das oben beschriebene zu realiseren ( Listbox mit allen client-names ) 
    
                         for ( int j = 0; j < MAX_CLIENTS ; j++ ) {
    		         if ( clients[j].client != INVALID_SOCKET && j != i ) {
    			    send ( clients[j].client , "\r\r##NEW CLIENT CONNECTED##\r\r", 28, 0 );
    			    Sleep(100); // Ist scheinbar nötig, sonst kommen die Strings als ein einziger an
    			    send ( clients[j].client, clients[i].name , strlen(clients[i].name) , 0 );
    
    			 }
    
    		     }
    		  }
                      // Falls das normaler Text ist soll der einfach erstmal an alle ebenfalls connectete Clients weitergegeben werden. Macht im Moment
                      // wenig Sinn, ist aber auch nicht das Problem.
    		  else {
    			  cout << clients[i].name << " sends : "  << buf << endl;
                              // Hier wird die Nachricht wieder weiter gegeben
    			  char temp[1224];
    			  strncpy(temp, clients[i].name, sizeof(temp) );
    			  strncat(temp, " sends : ", ( sizeof(temp) ) - strlen(temp) );
    			  strncat(temp, buf, ( sizeof(temp)) - strlen(temp)  );
    		          for(int j = 0; j < MAX_CLIENTS; j++) {
    		              if(j != i && ( clients[j].client != INVALID_SOCKET ) )
    			         send(clients[j].client, temp , strlen(temp) , 0 );
    		          }
    
    		  }
    		}
    	}
    
         }
      }
    

    Dieses "Prinzip" funktionierte bei den Console-Clients auch einwandfrei. Die Nachrichten wurden richtig weitergegeben, die Namen richtig gespeichert etc.
    Das Problem : Die Listbox des GUI-Clients hängt sich auf und kann nurnoch abgewürgt werden.

    Eben noc der Code, den der GUI-Client für die Connection ausführt :

    BOOL Connecter::Connect( char* ipAdress, int port, char* clientName ) {
         if( WSAStartup(MAKEWORD(2,0),&wsa) != 0 )
            return FALSE;
         s = socket (AF_INET, SOCK_STREAM , 0 );
         if(s == INVALID_SOCKET )
            return FALSE;
         addr.sin_family = AF_INET;
         addr.sin_port=htons(port);
         addr.sin_addr.s_addr=inet_addr(ipAdress);
         if( connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR)) == SOCKET_ERROR ) {
            MessageBox(NULL,"Connection failed ...", "Error", MB_OK );
            CleanUp();
            return FALSE;
         }
         // MessageBox ( NULL, "Connected sucessfully" , "Success", MB_OK);
         send(s,"\r\r##SENDING CLIENT NAME##\r\r", 28, 0 );
         Sleep(100);
         send(s, clientName, strlen(clientName), 0);
    
         return TRUE;         
    }
    

    Die Parameter wurden richtig übergeben, da ja die Verbindung etc. klappt. So, in der Message-Schleife des GUI-Clients habe ich es so gemacht, wie ihr vorgeschlagen habt : PeekMessage() mit select() :

    while (1)
        {
            if( PeekMessage (&messages, NULL, 0, 0, PM_REMOVE ) ) {
            /* Translate virtual-key messages into character messages */
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
            }
    
            else {
               if( !( gui.getConnecterClass().getSocket() == INVALID_SOCKET) ) {
                  FD_SET(gui.getConnecterClass().getSocket(), &set );
                  int rc = select(0,&set,NULL,NULL,NULL);
                  if( rc == SOCKET_ERROR) {
                     MessageBox( NULL , "Select failed ... Closing the programm", "Error" , MB_OK );
                     return 1;
                  }
                  if ( FD_ISSET( gui.getConnecterClass().getSocket() , &set ) ) {
                      char buf[1024];
                      // Normalerweise sendet der Server so : Name des senden Clients gefolgt von dem Text.
                      // Das ist aber nicht der Fall, wenn er eine special-message schickt, also müssen wir das erst überprüfen
                      rc = recv ( gui.getConnecterClass().getSocket() , buf , sizeof(buf) , 0 );
                      if ( rc == 0 || rc == SOCKET_ERROR ) {
                          gui.TerminateClients();
                          return 0;
                      }
    
                      buf[rc] = 0;
                      // Eben hier 
                      if( strcmp( buf , "\r\r##NEW CLIENT CONNECTED##\r\r" ) == 0 ) {
                         memset( buf , 0 , sizeof(buf ) );
                         rc = recv ( gui.getConnecterClass().getSocket() , buf , sizeof(buf) , 0 );
                         buf[rc] = 0;
                         //MessageBox(NULL, buf , "Got smth", MB_OK);
                         // Wie die special-message schon sagt, muss nun ein neuer Client hinzugefügt werden. addClient erwartet als Parameter den Namen des 
                         // hinzuzufügenden Clients
                         gui.addClient( buf );
                      }
                      else {
                         // Wie gesagt, wenn es KEINE special war, dann hat er zuerst den Namen geschickt und dann den Text 
                         // Also brauchen wir jetzt einen 2. Buffer um den Text zu speichern
                         char buf2[1024];
                         rc = recv ( gui.getConnecterClass().getSocket() , buf2, sizeof(buf2) , 0 );
                         // UpdateWindowOutput braucht als 1. Parameter den Text und als 2. den Chat-Partner, um das richtige Fenster zu finden
                         gui.UpdateWindowOutput( buf2 , buf );
                      }
                  }   
               }
            }
        }
    

    Oh man, je länger das hier wird desto unwahrscheinlich wird es, dass jemand sich die Mühe macht das hier alles durchzu lesen 😕
    Naja ... Ihr werdet euch denken können was ich als nächstest poste : GuiMaintainer::addClient.

    void GuiMaintainer::addClient( char* clientName) {
         std::string temp ( clientName);
         ClientNames.push_back( temp );
         SendMessage( hClientList[1], LB_ADDSTRING, 0,0);
         SizeListItems( hClientList[1] , ClientNames );
         SendMessage( hClientList[1] , WM_VSCROLL, SB_BOTTOM, 0);
    
    }
    

    Die alleine macht aber eig. garnichts, sondern die Arbeit wird da in der Call-back function erledigt. Die Funktionsweise habe ich von _Falke aus einem anderen Thread. Er hat sie geschrieben, ich sie nur angepasst. Funktioniert eig. auch. Naja, hiermal der relevante Call-Back Teil :

    case WM_DRAWITEM : {
    
                 if( wParam == ClientListBoxId ) {
                     // MessageBox(NULL,"Got smth", "In listbox" , MB_OK );
    
                    LPDRAWITEMSTRUCT lpd = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
                    switch (lpd->itemAction) {
                           case ODA_SELECT:
                           case ODA_DRAWENTIRE:
    
                           if( ClientNames.size() < lpd->itemID) { break; } 
                           SetBkMode(lpd->hDC, TRANSPARENT);
                           FillRect(lpd->hDC, &lpd->rcItem,
                                   (lpd->itemState & ODS_SELECTED)? GetSysColorBrush(COLOR_HIGHLIGHT): GetSysColorBrush(COLOR_WINDOW));
    
                           DrawText(lpd->hDC,
                                   ClientNames[lpd->itemID].c_str(),
                                   ClientNames[lpd->itemID].length(),
                                   &lpd->rcItem,
                                   DT_LEFT | DT_WORDBREAK );
                           case ODA_FOCUS:
                                break; 
                           }
                    } 
    
                 // NmbrOfChatWindows ist eine Int-variable in GuiMaintainer.h Sie wird jedes mal erhöht, wenn ein neues Chat-Fenster erstellt wird.
                 // Ich suche hier zunächst erstmal 
                 // Irgendwie glaube ich aber, dass (ChatWindowHandles[i]->output == GetDlgItem( ChatWindowHandles[i]-> mainWindow, wParam ) )  für jedes 
                 // Fenster true ist :/ 
                 for( int i = 0; i < NmbrOfChatWindows; i ++ ) {
    
                      if ( ChatWindowHandles[i]->output == GetDlgItem( ChatWindowHandles[i]-> mainWindow, wParam )   ) {
    
                           LPDRAWITEMSTRUCT lpd = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
                           switch (lpd->itemAction) {
                           case ODA_SELECT:
                           case ODA_DRAWENTIRE:
    
                           if(ChatWindowHandles[i]->OutputData.size() < lpd->itemID) { break; } 
                           SetBkMode(lpd->hDC, TRANSPARENT);
                           FillRect(lpd->hDC, &lpd->rcItem,
                                   (lpd->itemState & ODS_SELECTED)? GetSysColorBrush(COLOR_HIGHLIGHT): GetSysColorBrush(COLOR_WINDOW));
    
                           DrawText(lpd->hDC,
                                    ChatWindowHandles[i]->OutputData[lpd->itemID].c_str(),
                                    ChatWindowHandles[i]->OutputData[lpd->itemID].length(),
                                    &lpd->rcItem,
                                    DT_LEFT | DT_WORDBREAK );
                           case ODA_FOCUS:
                                break; 
                           }
                      }
                 }
    
                 break;
    
            }
    

    Puhh ... hier noch GuiMaintainer::SizeListItems()

    void GuiMaintainer::SizeListItems( HWND list, const std::vector<std::string>& Data) {
                       if(!Data.size()) return;
                       HDC hdc = GetDC(list);
                       SelectObject(hdc, reinterpret_cast<HFONT>(SendMessage(list, WM_GETFONT, 0, 0)));
                       bool erasebk = false;
                       for(size_t i=0;i<Data.size();++i) {
                           RECT itm;
                           SendMessage(list, LB_GETITEMRECT,i,reinterpret_cast<LPARAM>(&itm));
                           int h = DrawText(hdc,
                           Data[i].c_str(),
                           Data[i].length(),
                           &itm,
                           DT_LEFT | DT_WORDBREAK | DT_CALCRECT);
                           if(h != SendMessage(list, LB_GETITEMHEIGHT,i,0)) {
                           erasebk  = true; // wenn sich die Höhe eines Eintrags geändert hat, löschen wir den Hintergrund der Liste
                           SendMessage(list, LB_SETITEMHEIGHT, i, h);
                           }
                       }
                       ReleaseDC(list,hdc);
                       InvalidateRect(list, 0, erasebk); 
    }
    

    An dieser Stelle : Schonmal vielen Dank an die, die sich das alles durchgelesen haben ;P Ich sende das Posting jetzt erstmal ab. Wenn Euch Informationen ( Quellcode ) fehlen, dann postet das, werde dann das entsprechende Stück posten.

    Mfg !



  • Ich habe zwar keine Lust mir das jetzt alles durchzulesen, aber hast du eigentlich mal versuchst das ganze mit nem Debugger laufen zu lassen? Wenn dein Fenster abstürzt, scheint dein Programm irgendwo zu hängen, somit können die Nachrichten nicht mehr verarbeitet werden. Du musst jetzt nur rausfinden wo. Debugger wäre eine (gute(!)) Möglichkeit, sonst halt mit MessageBox() 😃



  • xD Ja also ich kann leider so garnicht mit dem Debugger umgehen, aber per MessageBoxe's hab ich folgendes rausgefunden : Aufhängen tut sich das Programm an der stelle :

    if( wParam == ClientListBoxId ) {
                     // MessageBox(NULL,"Got smth", "In listbox" , MB_OK );
    
                    LPDRAWITEMSTRUCT lpd = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
                    switch (lpd->itemAction) {
                           case ODA_SELECT:
                           case ODA_DRAWENTIRE:
    
                           if( ClientNames.size() < lpd->itemID) { break; }
                           SetBkMode(lpd->hDC, TRANSPARENT);
                           FillRect(lpd->hDC, &lpd->rcItem,
                                   (lpd->itemState & ODS_SELECTED)? GetSysColorBrush(COLOR_HIGHLIGHT): GetSysColorBrush(COLOR_WINDOW));
    
                           DrawText(lpd->hDC,
                                   ClientNames[lpd->itemID].c_str(),
                                   ClientNames[lpd->itemID].length(),
                                   &lpd->rcItem,
                                   DT_LEFT | DT_WORDBREAK );
                           case ODA_FOCUS:
                                break;
                           }
                    }
    

    Denn die auskommentierte MessageBox erscheint, und nach Klick auf "Ok" -> "Blabla funktioniert nicht mehr ... ".



  • Du musst den Befehl der das Problem verursacht schon genau feststellen.
    Das Switch wirds wohl nicht sein 😉



  • ;P Um genau zu sein, hängt sich das Ding direkt nachdem ich es erzeuge auf -.- Ich hab die gesammte Callback function etc. auskommentiert.

    Funktion zum erzeugen :

    BOOL GuiMaintainer::createClientList() {
    
         WNDCLASSEX windowClass;
         char szClassName[] = "ClientList";
         windowClass.hInstance = Inst;
         windowClass.lpszClassName = szClassName;
         windowClass.lpfnWndProc = WindowProcedure;      
         windowClass.style = CS_DBLCLKS;                 
         windowClass.cbSize = sizeof (WNDCLASSEX);
    
          /* Use default icon and mouse-pointer */
         windowClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
         windowClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
         windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
         windowClass.lpszMenuName = NULL;                 
         windowClass.cbClsExtra = 0;                     
         windowClass.cbWndExtra = 0; 
    
         windowClass.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
         if( !RegisterClassEx(&windowClass) ) {
             MessageBox(NULL,"CreateClientList() failed ! ", "Error" , MB_OK );
             return FALSE;
         }
    
         hClientList[0] = CreateWindowEx (
               0,
               szClassName,         
               "List of Chatpartner",       
               WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU ,
               CW_USEDEFAULT,       
               CW_USEDEFAULT,       
               150,                 
               350,                 
               hLoginHandles[MAINWINDOW],        
               NULL,                
               Inst,       
               NULL                 
               ); 
    
         hClientList[1] = CreateWindowEx (
               WS_EX_CLIENTEDGE,                   
               "LISTBOX",         
               "",       
               WS_VISIBLE | WS_CHILD | WS_VSCROLL | LBS_OWNERDRAWVARIABLE | LBS_NOTIFY | LBS_NODATA  , /
               3,       
               3,       
               130,                 
               309,                 
               hClientList[MAINWINDOW],        
               (HMENU)ClientListBoxId,                
               Inst,       
               NULL                 
               );
    
    }
    

    Sie wird erzeugt -> Hängt sich auf. Komisch.



  • So, ich korrigiere mich noch einmal :

    Das Fenster an sich funktioniert einwandfrei. Ich habe es testweise einfach mal so erzeugt und ich konnt es verschieben etc. ohne Probleme. Hat sich nicht aufgehängt.

    Aber sobald der Client zum Server eine Verbindung erfolgreich herstellt, hängt sich das Fenster komplett auf.

    while (1)
        {
            while( PeekMessage (&messages, NULL, 0, 0, PM_REMOVE ) ) {
                   if( messages.message == WM_QUIT )
                      return TRUE;
                   /* Translate virtual-key messages into character messages */
                   TranslateMessage(&messages);
                   /* Send message to WindowProcedure */
                   DispatchMessage(&messages);
            }
    
               if( !( gui.getConnecterClass().getSocket() == INVALID_SOCKET ) ) {
                   MessageBox(NULL,"Erfüllt ;=) ", "SUX", MB_OK);
                  FD_SET(gui.getConnecterClass().getSocket(), &set );
                  int rc = select(0,&set,NULL,NULL,NULL);
                  if( rc == SOCKET_ERROR) {
                     MessageBox( NULL , "Select failed ... Closing the programm", "Error" , MB_OK );
                     return 1;
                  }
                  if ( FD_ISSET( gui.getConnecterClass().getSocket() , &set ) ) {
                      char buf[1024];
                      // Usually the Server sends the Name of the Client first.
                      // This is not the case if he sends some kind of special message, thus we have to check if it is one
                      rc = recv ( gui.getConnecterClass().getSocket() , buf , sizeof(buf) , 0 );
                      if ( rc == 0 || rc == SOCKET_ERROR ) {
                          MessageBox(NULL,"SOCKET_ERROR","SOCKET_ERROR" , MB_OK);
                          // gui.TerminateClients();
                          return 0;
                      }
    
                      buf[rc] = 0;
                      // That happens here 
                      if( strcmp( buf , "\r\r####NEW CLIENT CONNECTED####\r\r" ) == 0 ) {
                         MessageBox(NULL,"Special messges OoOooo", "OoooooO", MB_OK);
                         memset( buf , 0 , sizeof(buf ) );
                         rc = recv ( gui.getConnecterClass().getSocket() , buf , sizeof(buf) , 0 );
                         buf[rc] = 0;
                         MessageBox(NULL, buf , "Got smth", MB_OK);
                         // gui.addClient( buf );
                      }
                      else {
                         // If the server did not send any special message, then it simply send the Client's name first
                         // Now he sends the Clients input next, which we are going to store in another buffer
                         char buf2[1024];
                         MessageBox(NULL,"NORMAL message OoooOOOoo", "OoOooOOO", MB_OK);
                         rc = recv ( gui.getConnecterClass().getSocket() , buf2, sizeof(buf2) , 0 );
                         // buf2 contains the textt o be updated, buf contains the clients name. And that's exactly what UpdateWindowOutput
                         // needs as information 
                         // gui.UpdateWindowOutput( buf2 , buf );
                      }
                  }   
               }
            }
    

    Wie man sieht : Ich habe alles, was irgendwelche Funktionen von GuiMaintainer callt auskommentiert. TROTZDEM hängt es sich noch auf ! Sobald eine Verbindung steht, und somit if( !( gui.getConnecterClass().getSocket() == INVALID_SOCKET ) erfüllt ist, hängt das Fenster sich auf. Ich schlaf jetzt mal drüber, villeicht finde ich morgen irgendwo die Logik ...



  • An deiner Stelle würde ich mir mit dem Debugger mal ansehen, wo innerhalb dieser Funktion dein Programm so lange zu tun hat, daß es keine Zeit mehr hat, auf Windows-Nachrichten zu reagieren.



  • Ok gut, dann werde ich es morgen nochmal in VSC++ compilen, denn Dev C++ hat keinen Debugger ( zmnd meint das Programm immer, dass es irgendwie nicht funktioniert ) .

    Soweit ich es mit MessageBoxen überprüft habe, hängt es sich genau hier auf :

    int rc = select(0 ,&set, NULL , NULL, NULL);
    

    Also beim select Aufruf. Unlogisch. Der Aufruf wird nie beendet, denn die MessageBox direkt nach dem Aufruf erscheint nie. Finde ich komisch, eig. sollte select doch einfach einen 0 returnen, wenn es failt, und nicht sich aufhängen.

    Auf jeden Fall mal danke schonmal fürs Lesen & Posten 😉



  • Du hast select() noch nicht ganz verstanden. Letzter Parameter ist ein Timeout 😉

    Edit:

    Dev C++

    Böse!


Anmelden zum Antworten