[CLI] [Windows Forms] Dodatkowy wątek do komunikacji

0

Witam,
tworze program do komunikacji sieciowej, chcę przerzucić część odpowiedzialną za połączenie z serwerem, za które obecnie odpowiada Button Connect na nowy wątek. Projekt jest oczywiście z użyciem formatki. Chce żeby wyglądało mniej więcej tak. User naciska button Connect, w kodzie obsługi jest utworzenie nowego wątku, który zajmuje się połączeniem z serwerem i problem w tym, ze nie wiem jak to zrobić
Próbuje coś takiego :

System::Void ConServ(void * ptr) {
			 const char * hostName = "77.253.29.37";
			 const char * port = "1234";
			 char * str = "client -> ";
			 System::String ^s = gcnew String(str);
			 WRequiredVersion = MAKEWORD(2, 0);
			 if (WSAStartup(WRequiredVersion, &WData) != 0) {
				 this->logInfo->AppendText(s + "WSAStartup failed!\n");
			 } else {
				 this->logInfo->AppendText(s + "WSAStartup - OK\n");
			 }

			 //look up server's IP address
			 lpstServerEnt = gethostbyname(hostName);
			 if(! lpstServerEnt) {
				 this->logInfo->AppendText(s + "Can't get the sever's IP address\n");
			 }

			 //create socket
			 SSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
			 this->logInfo->AppendText(s + "Socket created\n");

			 //server info
			 memset(&stServerAddr, 0, sizeof(struct sockaddr));
			 stServerAddr.sin_family = AF_INET;
			 memcpy(&stServerAddr.sin_addr.s_addr, lpstServerEnt->h_addr, lpstServerEnt->h_length);
			 stServerAddr.sin_port = htons(atoi(port));

			 //connect to the server
			 nConnect = connect(SSocket, (struct sockaddr*)&stServerAddr, sizeof(struct sockaddr));
			 if (nConnect < 0) {
				 this->logInfo->AppendText(s + "Can't connect to the server\n");
			 } else {
				 connected = true;
				 this->logInfo->AppendText(s + "Connected\n");
			 }

			 // odbiera liczbę funkcji
			 nBytes = recv(SSocket, (char*)&liczbaFunkcji, sizeof(int), 0);

			 // tworzy dynamiczną tablice przechowującą dane o funkcjach
			 if (flag) {
				 FunList = new struct funkcja[liczbaFunkcji];
				 flag = false;
				 }
			
			 // odbiera informacje o funkcjach
			 nBytes = recv(SSocket, cbBuf, sizeof(cbBuf), 0);
			 char nazwa[20];
			 char opis[128];
			 for (int i=0; i<liczbaFunkcji; i++) {
				 FunList[i].id = (int)cbBuf[i*rozmiarStruct];
				 FunList[i].argNum = (int)cbBuf[4 + i*rozmiarStruct];
				 for(int j=0; j<sizeof(FunList[i].name); j++)
					 nazwa[j] = (char)cbBuf[8 + i*rozmiarStruct + j];
				 for(int j=0; j<sizeof(FunList[i].describe); j++)
					 opis[j] = (char)cbBuf[28 + i*rozmiarStruct + j];
				 FunList[i].name = nazwa;
				 FunList[i].describe = opis;
			 }
			 _endthread();
			 }

to jest funkcja, która będzie znajdować się w nowo utworzonym wątku
w obsłudze kliknięcia natomiast mam

 _beginthread(&klient::Form1::ConServ, 0, (void*)0);

no i zwraca błąd

1>c:\projekty\sk - projekt\klient\klient\Form1.h(335) : error C3374: can't take address of 'klient::Form1::ConServ' unless creating delegate instance

może ktoś bawił się formatką z użyciem kilku wątków i jest w stanie mi pomóc bo ja nie wiem jak to zrobić, żeby funkcjonowało

w ramach wyjaśnień funkcję tą umieściłem też w nagłówku, w którym znaduje się cała obsługa formatki zaraz nad obsługą zdarzenia kliknięcia na button Connect. tak samo funkcja jest typu System::Void a nie zwyczajnie void, ponieważ bez tego nie mogę uzyskać dostępu do formatki, szczególnie chodzi mi tu o komponent RichTextBox na którym ma wyświetlać aktualny stan łączenia

0

jakakolwiek metoda ktora w parametrach albo wartosciach zwracanych ma jakikolwiek typ z .net'a - np. system::void, system::int, system::stream zamiast zwyklych natywnych typow void, int, std::iostream etc najprawdopodobniej nie bedzie sie w ogole nadawala do uzytku we wspolpracy z natywnymi mechamizmami. zwlaszcza tymi niskopoziomowymi bazujacymi na recznych przerzutowaniach, patrz np. ow beginthreadex i parametry startowe watku.. ale do rzeczy:

kompilator wywala blad, poniewaz sygnatura Twojej metody to System::Void (Form1::)(void ) i rozni sie to znacznie od void()(void) wymaganej przez beginthreadex:

  • po pierwsze, System::Void to NIE TO SAMO co void, wiec nie pasuja warotsci zwracane
  • po drugie, taki 'drobiazg', Twoje cuś jest metodą, stad (Form1::*), zas beginthreadex wymaga funkcji, mam nadzieje ze rozróżniasz..

co zrobic? dwie drogi:

  • native:
    po pierwsze zmienic -jakos- System::Void na void. jesli kompilator nie pozwoli uzyc takiego typu wewnatrz ref-class Form1 - no to sorry, musisz poradzic sobie na okolo i wyrzucic te metode z tej klasy gdzies na zewnatrz, np. do nowej nie-ref klasy. musisz miec typ zwracany void.
    po drugie, nie moze byc to zwykla metoda. jako ze beginthread potrzebuje () a nie (klasa::), to musi to byc funkcja albo statyczna metoda klasy. jesli z natury tego kodu wynika ze musi on miec dostep do obiektu Form1 - podaj mu ten jakos obiekt przez parametr watku.
  • managed:
    Zamiast beginthreadex uzyj obiektow System::Thread, zamiast wsk-na-metode/funkcje uzyj delegatow na metode obiektu Form1. see google i tutoriale od .Net threads

btw. z racji tego, ze u Ciebie jest to metoda i w dodatku .Net'owska, kompilator nie pozwala pobrac jej adresu w ogole i stad taki a taki komuniakt dostales -- w .Net adresy mozna pobierac tylko do danych i to tez bardzo rzadko i w szczegolnych przypadkach. za 'wskazniki-do-metod/funkcji' robia specjalne konstrukcje nazywane 'delegatami', co w istocie jest mala strukturka zawierajaca wskaznik-do-metody plus wskaznik-na-obiekt do ktorego ta metoda nalezy. nie musze chyba wspominac ze delegat nie nada sie do beginthreadex bo chyba slychac ze nie jest to to samo co wskaznik-na-funkcje :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1