I am not that qualified in C++ programming but I really can't get through this issue. My project is as follows : Connecting to a WIFI server with the TCP protocol . The server keeps sending lines of text : no problem . It systematically connects. A dedicated thread is cycling receiving the text and displaying it in an edit window. It is supposed to terminate when I click on a "disconnect" button. But I can't click on that button because I get a message (Cancel, Retry, Ignore) telling me Abort() has been called. Meanwhile the messages are still displayed and the parallel debug window shows me the thread comfortably going on working.
This is the code of my WndProc :
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_ACTIVATEAPP:
{ Create_incoming_NMEA_messages_box();
Create_info_message_box();
Create_push_button();
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDC_MAIN_BUTTON: // connect - disconnect
{
if (!Connected)
{
if (Connect_addr(szServer, szPort) == 0) // == 0 => connected
{
Connected = true;
SendMessage(hEditOut, WM_SETTEXT, NULL, (LPARAM)"Connected at Host = 10.0.0.1 / Port = 10111");
Button_SetText(hWndButton, "Disconnect");
thread TCPThread(Loop_while_connected); // thread constructed and launched
}
}
else {
Connected = false;
SendMessage(hEditOut, WM_SETTEXT, NULL, (LPARAM)"Disconnected");
//TCPThread.join();
Button_SetText(hWndButton, "Connect");
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Just to be precise the Connect_addr(szServer, szPort) function is as follows :
int Connect_addr(char* host, char* port)
{
// Set up Winsock INITIALIZATION
WSADATA WsaDat;
int nResult = WSAStartup(MAKEWORD(2, 2), &WsaDat);
if (nResult != 0)
{
MessageBox(hWnd, "Winsock initialization failed", "Critical Error", MB_ICONERROR);
SendMessage(hWnd, WM_DESTROY, NULL, NULL);
}
struct addrinfo hints; // defines address type
struct addrinfo* result, * rp;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // Allow IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP socket
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP;
int s = getaddrinfo(host, port, &hints, &result);
// getaddrinfo() returns a list of address structures.
// Try each address until we successfully connect(x). x = socket ID
// If socket(x) (or connect(x)) fails, we (close the socket
// and) try the next address.
int resconn = -1; // result of the connection attempt
for (rp = result; rp != NULL; rp = rp->ai_next) // rp = pointer to the chained list of all IP addresses managed by the client machine
{
ConnectSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (ConnectSocket == -1)
continue;
resconn = connect(ConnectSocket, rp->ai_addr, rp->ai_addrlen);
if (resconn == -1)
{
resconn = WSAGetLastError();
MessageBox(0, "Non connect\u00E9", "Erreur connexion", MB_ABORTRETRYIGNORE);
}
else break; // Success
}
freeaddrinfo(result); // No longer needed
return resconn;
}
This function works fine. The problem seems to be with thread TCPThread(Loop_while_connected) in the WindProc code (case IDC_MAIN_BUTTON).
The thread function is Loop_while_connected here:
const unsigned HISTORY_BUFF_SIZE = 1000000;
char szHistory[HISTORY_BUFF_SIZE] = { 0 }; // NMEA messages accumulating buffer
int nKr = 0; // sums the received Kr to reset szHistory to start before saturating the buffer
const unsigned int Buff_Size = 10240;
void Loop_while_connected()
{
int inDataLength = 0;
if (Connected)
do
{
char szIncoming[Buff_Size];
ZeroMemory(szIncoming, Buff_Size);
inDataLength = 0;
inDataLength = recv(ConnectSocket, szIncoming, Buff_Size, 0);
if (inDataLength > 0)
{
strncat_s(szHistory, _countof(szHistory), szIncoming, inDataLength);
nKr += inDataLength;
SendMessage(hEditIn, WM_SETTEXT, sizeof(szIncoming) - 1, reinterpret_cast<LPARAM>(szHistory));
PostMessage(hEditIn, EM_SETSEL, 0, -1); // Select all
PostMessage(hEditIn, EM_SETSEL, -1, -1); // Unselect and stay at the end pos
PostMessage(hEditIn, EM_SCROLLCARET, 0, 0); // Set scrollcaret to the current Pos
}
if (nKr >= HISTORY_BUFF_SIZE - Buff_Size) {
ZeroMemory(szHistory, sizeof(szHistory));
nKr = 0;
}
} while (Connected);
}
It starts like this :
When I click on connect it connects but issues an error message like this while the text is always scrolling :
Now if I hit "Retry to debug" as indicated the thread actually stops and I get the debug window showing me an error at the end of the destruction procedure.
I surely have made something stupid somewhere . I have checked that my thread was joinable as soon it was launched but I still can't understand why my call to TCPThread.join() in the WndProc procedure on disconnecting is rejected by the compiler. Maybe both problems are related ? Than you in advance for your help.
In fact there is nothing properly stupid there. Microsoft VC++ Win32 does not seem to comply to the C++ 11 multithreading "simplicity"(constructor/destructor) . A line like
compiles without problem but eventually bugs at run time.
The solution is to use _beginthread instead like this
provided the function Loop_while_connected is rendered consistent with the call to _beginthread by passing a pointer to the thread ID as a parameter in its header like this :
{ }