CreateThread - keine Memberfunktion erlaubt ?
-
http://msdn.microsoft.com/en-us/library/bb761313(v=vs.85).aspx schrieb:
If the list box has an owner-drawn style but not the LBS_HASSTRINGS style, the buffer pointed to by the lParam parameter receives the value associated with the item (the item data).
Das Problem kann ausgeschlossen werden?
Der nächste Schritt wäre jetzt mal den Rückgabewert von
Hmmmm schrieb:
SendMessage( (HWND)lParam , LB_GETTEXT , index , (LPARAM)buffer );
auszuwerten. Ist der irgendeine Zahl? Oder 0? Oder LB_ERR?
Woher weist du, dass der Index richtig bestimmt wird? Ich rate dir wirklich dazu, den Umgang mit dem Visual Studio Debugger zu lernen. Das ist nicht schwer, aber hilft enorm

Edit:
Hmmmm schrieb:
Für die Namen werde ich sehr wahrscheinlich einen Limit auf 50 bytes oder so setzen, also ist das kein Problem.
Dann lege dafür eine Konstante fest. Je nach C oder C++
#define NICKNAME_MAX_LEN 50 // C static const int nickname_max_len = 50 // C++Falls du dich für C++ entscheidest, solltest du außerdem auch C++ Casts verwenden. (static_cast<>, reinterpret_cast<>, etc.)
-
Oh, dein Quote hat mich an folgendes errinert ;P : Habe für die Listbox LBS_NODATA als flag, denn ich speichere die Namen bzw alles was diese Listbox je enthalten wird in einem vector.
Somit kann ich einfach den Namen aus dem Vector suchen eben mit meiner "index" variable als index ;P Klappt so auch.Ja, sollte ich warsch. echt mal tuen ;P Habe es per MessageBox überprüft ( itoa + Messagebox ).
Jetzt muss ich nurnoch rausfinden, wie ich a) Einträge aus meiner Listbox entferne ( sodass die Einträge auch "nachrutschen" ) und b) bestimmte Namen aus dem vector entferne und dafür sorge, dass die einträge "nachrutschen". Sollte aber nicht zu wild sein ( zmnd b) ).
Zu den C++ casts werde ich mich auch mal überreden, finde die nur ätzender zu schreiben ;P Außerdem weiss ich nie so recht, ob ich static_cast oder reinterpret_cast oder w/e nehmen soll ... Muss ich mich auch nochmal zu belesen

Btw : Wieso #define in C und const in C++ ? const geht wohl auch in C ? Und wieso genau static ?
-
Hmmmm schrieb:
Btw : Wieso #define in C und const in C++ ? const geht wohl auch in C ? Und wieso genau static ?
Das ist für die örtliche Style Polizei

static const x ist #define vorzuziehen, da es Typsicher ist. Soll heißen:
static const int val = "hallo!";Wird einen Fehler verursachen. In C ist/war
static const int val = 50; char test[val];aber nicht möglich. Deswegen nimmt man dort immer noch #define.
-
Oke
Klingt plausibel ^^Mal ne andere Frage, eher nicht zu WinApi, sonder C++ : Wtf soll man mit diesen Iteratoren anfangen ? Also zB :
std::vector < std::string >::iterator pos; pos = find ( clientNames.begin() , clientNames.end() , clientName ); if ( pos != clientNames.end() ) { // do something } else { // do it not }Eigentlich wollte ich den Index von irgendeinem Client-Namen rausfinden, aber mit diesem iteratoren-typ kann ich garnichts anfangen. Lässt sich ja schliesslich nicht nach int casten oder sonstiges. Keine Ahnung wie ich das also mache ;P
-
Iteratoren haben den Vorteil, daß du damit auf beliebigen Datenstrukturen arbeiten kannst - der Zugriff auf eine verkettete Liste (std::list<>) funktioniert genauso wie auf ein dynamisches Array (std::vector<>) oder einen Binärbaum (std::set<>/std::map<>). Mit dem gefundenen Iterator kannst du jetzt weiterarbeiten wie mit einem Zeiger - du dereferenzierst ihn, um an die dahinterstehenden Daten zu gelangen
Wenn du den Index des gefundenen Elements heranwillst, kannst du std::distance() verwenden (für vector<> geht auch die Iterator-Differenz):
std::vector < std::string >::iterator pos; pos = find ( clientNames.begin() , clientNames.end() , clientName ); if ( pos != clientNames.end() ) { int index = std::distance(clientNames.begin(), pos); // oder index = pos-clientNames.begin(); } else { // do it not }PS: Aber ich würde im Ernstfall keine parallelen Arrays verwenden, sondern alle Informationen zu einem Client in eine Struktur zusammenfassen und dann einen
std::vector<ClientData>verwenden.
-
Achso, das ist natürlich praktisch, danke !
Noch eine Frage : Was passiert in dem Fall, wenn das gesuchte Element an der letzten Stelle ist ? Würde das dann nicht fehlschlagen. Denn eig. ist die bedingung if ( pos != clientNames.end() ) nicht erfüllt, aber das Element wurde trotzdem gefunden.
Zu dem gesamt-struct thema : Hmm, wäre das denn besser ? Dann müsste ich immer ewig oft den '.' operator benutzten a la ClientStruct.clientList.ClientNames[index].c_str(); Wie das aussieht

-
Hmmmm schrieb:
Noch eine Frage : Was passiert in dem Fall, wenn das gesuchte Element an der letzten Stelle ist ? Würde das dann nicht fehlschlagen. Denn eig. ist die bedingung if ( pos != clientNames.end() ) nicht erfüllt, aber das Element wurde trotzdem gefunden.
clientNames.end() zeigt nicht auf das letzte Element deiner Liste, sondern hinter das letzte Element.
Zu dem gesamt-struct thema : Hmm, wäre das denn besser ? Dann müsste ich immer ewig oft den '.' operator benutzten a la ClientStruct.clientList.ClientNames[index].c_str(); Wie das aussieht

Viel länger als mit den parallelen Arrays wird der Code dadurch nicht, eher im Gegenteil. Vergleich mal folgendes:
pos = find(ClientNames.begin(),clientNames.end(),name); if(pos!=ClientNames.end()) { int index = distance(clientNames.begin(),pos); return ClientIPs[index]; } // vs. pos = find_if(Clients.begin(),Clients.end(),compare_name(name)); if(pos!=Clients.end()) { return pos->IP; }(außerdem mußt du nicht bei jedem Login und Logout darauf achten, daß die wirklich alle Client-Daten-Arrays synchron zueinander änderst)
-
Ja okay, das stimmt wohl schon, aber ich denke darum kümmere ich mich zum Schluss nochmal.
Momentan habe ich mal wieder ein Problem, seufz. Beschreibung : Ich schicke an einen neu gejointen Client alle Client-Namen. Das Problem : Er bekommt die namen als EINEN string anstatt als mehrere einzelne. Trotz Sleep()-call zwischen den send's !
Code, Clientside
... else if ( buf[0] == '1' ) { char temp[9]; // Hier bekomme ich die Zahl gesendet, wobei ich die vorangehende 1 ignorieren muss. Siehe server-code for ( int k = 0; k < strlen(buf) - 1; k++ ) { temp[k] = buf[k+1]; } temp[strlen(buf) -1 ] = 0; MessageBox( NULL, temp , "Temp is ", MB_OK); // Check ob die Zahl richtig konvertiert wurde, positiv int count = atoi( temp ); for ( unsigned int k = 0; k < count ; k ++ ) { char temp2[200]; rc = recv ( gui.getConnecterClass().getSocket(), temp2 , sizeof(temp2) , 0 ); temp2[rc] = 0; MessageBox( NULL , temp2 , "temp 2 is : " , MB_OK ); // Hier wird das Problem immer klar : Die namen sind als ein String angekommen gui.addClient( temp2 ); } } ...Code, Serverside
... if(buf[0] == '0' ) { // 0 an erster Stelle = neuer Client for ( int count = 0; count < strlen(buf) - 1 ; count ++ ) { // Den struct mit dem Namen füllen. Die message sieht also so aus : clients[i].name[count] = buf[count+1]; // "0NameDesClients". Ist auch alles richtig, hab ich geprüft } clients[i].name[strlen(buf) -1 ] = 0; for ( int j = 0; j < MAX_CLIENTS ; j++ ) { // Den Namen an alle anderen Clients weitergeben, wieder steht 0 für neuer Client if ( clients[j].client != INVALID_SOCKET && j != i ) { // Ist auch alles richtig, der Name des Clients wird bei den anderen richtig char temp[250] = "0"; // hinzugefügt strcat(temp,clients[i].name); send( clients[j].client, temp, strlen(temp) , 0 ); } } if ( clientNames.size() > 0 ) { // Ein std::vector < std::string > char temp[10] = "1"; // 1 steht für : "Ich sende jetzt ein Zahl und soft must du loopen, um alle Namen zu empfangen char temp2[9]; itoa( clientNames.size() , temp2 , 10 ); strcat ( temp , temp2 ); cout << temp << endl; // Zahl wird richtig konvertiert send ( clients[i].client , temp, strlen(temp) , 0 ); Sleep(100); // Der genannte Sleep() da sonst zu schnell hintereinander gesendet wird und der String als einer ankommt for ( unsigned int y = 0; y < clientNames.size(); y++ ) { send ( clients[i].client , clientNames[y].c_str() , strlen(clientNames[y].c_str()), 0 ) ; Sleep(500); // Noch ein sleep, damit die Namen auch nicht als einer ankommen. Übertrieben lang ja, ich wollte nur sehen obs hilft } // Tut es aber nicht, der String kommt als einer an -.- } cout << "Clients[i].name : " << clients[i].name << endl; // Nochmal ein Check ob der Name richtig bestimmt ist, ist er auch clientNames.push_back( clients[i].name ) ; // Namen zu der Namens-Liste hinzufügen } ...Jetzt mal ein Beispiel, damit das Problem klar wird :
Client 1 connected mit Name " Let's ". Server nimmt ihn an, speichert den Namen fertig.
Client 2 connected mit dem Namen "test ". Server nimmt ihn an, schickt an Client 1 "0test " woraufhin dieser "test " auf seine Client-List setzt.
Weiter schickt der Server "11" ( Messagebox1 : "1" ) an Client 2 , woraufhin dieser 1 mal loopt und dabei " Let's " ( MessageBox2 : " Let's " ) auf seine Client-List setzt.
Client 3 connected mit dem Namen "this !". Server schickt an Client 1 und 2 "0this !", woraufhin beide erfolgreich "this !" auf ihre Client-List setzen.
Weiter schickt der Server an Client 3 "12" ( MessageBox1 : 2 ) woraufhin folgendes passiert : MessageBox2 ist : "Let's test" beim ersten mal loopen des Clients. Daraufhin callt Client 3 im 2. loop-Durchgang nochmal recv(), da der Server aber schon alles gesendet hat, blockiert recv() die Message-Schleife und Client 3 hängt sich auf.
-
Da solltest du ein Kennzeichen festlegen, wo ein String zu Ende ist und der nächste anfaängt (entweder du überträgst vorher die Stringlänge oder du sendest den Null-Terminator mit). Der Client muß natürlich auch dieses Kennzeichen kennen und die empfangenen Daten entsprechend auswerten.
-
Anders gehts wohl nicht ?
Wollte das eigentlich vermeiden, wird ganzschön anstrengend. Vor allem wenn ich berücksichtigen muss, dass send ein limit von 1024 byte hat, soweit ich weiss. Dann müsste ich davor wieder ein send verbrauchen, um mitzuteilen wie lang der String ist ?
Dachte das geht so in Ordnung, wie ich das gemacht habe, aber send() ist wohl nicht ganz so genau wie man sich das vorstellt.
-
send hat kein Limit von 1024 Byte. Und wieso ist es nicht so, wie DU es Dir vorstellst? Es sendet die Daten an den Empfänger, was hättest Du erwartet?
-
Ändere
send( clients[j].client, temp, strlen(temp) , 0 );in
send( clients[j].client, temp, strlen(temp) + 1 , 0 );Dann bekommt der Empfänger das String-Ende Zeichen '\0' mitgesendet.
-
Es hat kein Limit bei 1024 ? Hat es denn ein Limit ? Ich habe einmal diese Funktion für die maximale Msg-Size ausprobiert, ergibt bei mir aber immer 0.
Nun, wir wurde folgendes gesagt : send calls setzten gerne mal strings zusammen und reissen sie ausseinander, deswegen schreibt man sich package-header.Ohh, jetzt hab ich das alles schon umgeändert, sodass ein einziger String gesendet wir und der Client diesen dann unterteilt
Welche Variante wäre denn "besser" ? Wenn send() halt ein bestimmtes Limit hat ist das mit einem String relativ aufwenidiger. Allerdings werden bei meiner ersten Variante sehr viele send-calls gemacht und ich weiss nicht wie gut bzw wie schlecht das ist.
Danke auf jeden Fall schonmal für den Hinweis
-
Hmmmm schrieb:
Es hat kein Limit bei 1024 ? Hat es denn ein Limit ? Ich habe einmal diese Funktion für die maximale Msg-Size ausprobiert, ergibt bei mir aber immer 0.
Nun, wir wurde folgendes gesagt : send calls setzten gerne mal strings zusammen und reissen sie ausseinander, deswegen schreibt man sich package-header.Das Verhalten hast du ja schon in der Praxis kennengelernt
(als du deine Client-Namen übermitteln wolltest)Ansonsten dürfte das Socket-System schon dafür sorgen, daß die Daten in der günstigsten Form übertragen werden.
-
Naja, ob das an der von Belli erwähnten Sache lag oder am send() selber weiss ich leider nicht.
Bin schon wieder bei einem neuen Problem.
Laut MSDN : http://msdn.microsoft.com/en-us/library/bb775183(v=vs.85).aspx bräuchte ich hier nur den index + LB_DELETESTRING zu senden und schon würde das entsprechende item gelöscht werden. Allerdings wird bei mir IMMER das letzte Element in der Listbox gelöscht, sogar wenn ich index hardcode, zb :SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );. Es wird trotzdem das letzte Element gelöscht ;O
[quote = 'MSDN']
If an application creates the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the system sends a WM_DELETEITEM message to the owner of the list box so the application can free any additional data associated with the item. [/quote]Das trifft zwar bei mir zu, kann aber nicht herrauslesen, dass das ein Problem für das Löschen des Eintrages an sich wäre. Ich könnte, falls ich wollte , halt durch WM_DELETEITEM weitere Informationen beziehen, aber das wars auch.
-
Hmmmm schrieb:
send calls setzten gerne mal strings zusammen und reissen sie ausseinander
Die setzen weder was zusammen, noch reißen sie was auseinander. Sie senden einfach die Daten an den Empfänger.
Aber: Wie ich oben schon mal in anderem Zusammenhang erwähnte, kann/darf man sich nicht darauf verlassen, dass ein Aufruf von recv haargenau das liest, was ein send geschickt hat.
Stell Dir das so vor:
send versendet die Daten an den Empfänger, die Daten werden in einem Puffer vorgehalten. Bei weiteren sends werden die nächsten Daten hinten angehängt, usw.recv beim Empfänger liest jetzt aus diesem Puffer. recv hat aber keine Ahnung davon, wieviel sends der Sender ausgeführt hat, es 'sieht' nur den Puffer und die darin befindlichen Daten und liest aus, was es kriegen kann.
Das kann 1. dazu führen, dass zB mit einem send 1000 Byte versendet werden, ein recv aber nur 300 Byte liest. Deshalb - wie in einem früheren Posting erwähnt - braucht man für die Kommunikation häufig ein Protokoll. Etwa in der Art, dass beim send immer erst 4 Byte mit der Länge der folgenden Message gesendet wird, recv diese 4 Byte liest und dann so lange weiterliest, bis es genau die entsprechende Anzahl Byte bekommen hat.
2. kann das zu dem von Dir beobachteten Verhalten führen, es wird zB 5 mal send mit je 1000 Byte ausgeführt; beim recv kann nun von 1 bis 5000 alles 'erwischt' werden ...
-
cooky451 schrieb:
Wenn überhaupt, dann geht das so:
class MyClass { public: static void foo(void *param) { std::cout << GetCurrentThreadId() << std::endl; } }; int main() { for (int i = 0; i < 50; ++i) CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&MyClass::foo), 0, 0, 0); Sleep(20000); return 0; }Ich weiß aber nicht, welches Verhalten garantiert wird.
Falls du die CRT nutzt, sollten eh _beginthread/ex etc. herhalten.
Siehe
http://msdn.microsoft.com/de-de/library/kdzttdcb(v=vs.80).aspxDer Herr Richter hatte glaube ich auch mal einen Blogeintrag dazu geschrieben..
Nur so als Hinweis: Mit dem Cast nach LPTHREAD_START_ROUTINE den Kompiler zum Schweigen zu bringen ist nicht sehr nett. Verpasse der Thread Routine die korrekte Signatur, Rückgabetyp und Calling Convention und der Kompiler zeigt auch ohne Cast keinen Fehler mehr!!
-
Gut, dann werde ich wohl zum Anfang jeden Strings die größe mit übergeben. Dann sollte ich bei jedem recv()-call wohl auch prüfen ob rc < gesendeteGröße ist, wenn ja dann nochmal recv() callen, right ?
Aber bei meinem vorhin erwähnten Problem komme ich immernoch nicht weiter.
SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );-> Löscht immer das letzte Item der Listbox. Trotz des Hardcodings von index ( wPara ) ;O
-
Hmmmm schrieb:
SendMessage ( GetDlgItem( hClientList[0] , ClientListBoxId ) , LB_DELETESTRING , 2 , 0 );-> Löscht immer das letzte Item der Listbox. Trotz des Hardcodings von index ( wPara ) ;O
Nö. Das tut es nicht...
-
Bei mir leider schon

Screeni : http://imageupload.org/?d=4A0697231