0

I cant seem to shake this compiler error.

Error   1   error LNK2001: unresolved external symbol "public: __thiscall Socket::Socket(void)" (??0Socket@@QAE@XZ) C:\arma-to-socket\ConsoleApplication5\ConsoleApplication5\ConsoleApplication5.obj   ConsoleApplication5
Error   2   error LNK1120: 1 unresolved externals   C:\arma-to-socket\ConsoleApplication5\Release\ConsoleApplication5.exe   ConsoleApplication5

As far as I can tell I have linke the correct lib files:

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

And included everything I think I need:

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string> 

Complete Source code:

Console app to debug (will be compiled to dll later in another project): main cpp file

// ConsoleApplication5.cpp : Defines the entry point for the console application.
//

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#include "stdafx.h"
#include <iostream>
#include "Socket.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{       
     char myIP[10] = "127.0.0.1";
     Socket mySocket;
     mySocket.Init(*myIP);
     mySocket.Connect();
     mySocket.Send("hello world");

     return 0;
}

Socket.h

#pragma once

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string> 

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT "9999"
using namespace std;
class Socket
{
public:
     Socket();
     Socket(CHAR);
     void Init(CHAR);
     int Connect();
     int Send(string input);
     string Recieve();
     int Disconnect();
     string SendRecieve(string input);
     int getStatus();
     char getStatusMsg();
     ~Socket();
private:
     struct addrinfo *result = NULL,
         *ptr = NULL,
         hints;
     char *sendbuf = "this is a test";
     char recvbuf[DEFAULT_BUFLEN];
     int iResult;
     int recvbuflen = DEFAULT_BUFLEN;
     int status;
     CHAR statusMsg;
     SOCKET ConnectSocket;
     CHAR addressChar;
     CHAR *addressPtr;
     WSADATA wsaData;
};

Socket.cpp:

#include "stdafx.h"
#include <string> 
#include "Socket.h"

Socket::Socket(CHAR address){
    Init(address);

}



void Socket::Init(CHAR address)
{
    addressChar = address;
    addressPtr = &addressChar;

    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
        *ptr = NULL,
        hints;
    char *sendbuf = "this is a test";
    iResult = getaddrinfo(addressPtr, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        statusMsg = ("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        status = 1;
    }

    // Attempt to connect to the first address returned by
    // the call to getaddrinfo
    ptr = result;

    // Create a SOCKET for connecting to server
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
        ptr->ai_protocol);
    if (ConnectSocket == INVALID_SOCKET) {
        statusMsg = ("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        status = 1;
    }
    status = -1;
}

int Socket::Connect() {
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }
    // Should really try the next address returned by getaddrinfo
    // if the connect call failed
    // But for this simple example we just free the resources
    // returned by getaddrinfo and print an error message

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        //statusMsg = "Unable to connect to server!";
        WSACleanup();
        status = 1;
    }
    if (status = 1){
        return 1;
    }
    else {
        return 0;
    }

};

int Socket::Send(string input){
    char *sendbuf = (char*)input.c_str();
    // Send an initial buffer
    iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        statusMsg = ("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }

    statusMsg = ("Bytes Sent: %ld\n", iResult);

    // shutdown the connection for sending since no more data will be sent
    // the client can still use the ConnectSocket for receiving data
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        statusMsg = ("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }
    if (status = 1){
        return 1;
    }
    else {
        return 0;
    }
};

string Socket::Recieve() {
    string rtn = "";
    // Receive data until the server closes the connection
    do {
        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0){
            string rtn = recvbuf;
        }
        //else if (iResult == 0)
        //statusMsg = ("Connection closed\n");
        else{
            statusMsg = ("recv failed: %d\n", WSAGetLastError());

        }
    } while (iResult > 0);
    return rtn;

};

int Socket::Disconnect(){
    // shutdown the send half of the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        //printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        status = 1;
    }
    return 0;

};

string Socket::SendRecieve(string input){
    Send(input);
    return Recieve();

};

int Socket::getStatus(){

    return status;
}
char Socket::getStatusMsg(){
    return statusMsg;
}
Socket::~Socket()
{
    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    status = 0;
};

Note: when in the intended target project and compiled to dll it compiles without errors, but crashes at runtime.

Main file from target project:

// threaded_example.cpp : Defines the exported functions for the DLL application. 
// original threading arma plugin from http://killzonekid.com
//

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h" 
#include <string> 
#include <unordered_map> 
#include <thread> 
#include <mutex> 
#include <atomic> 
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>


#include "Socket.h"


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 1024
#define DEFAULT_PORT "9999"


//todo: pass parameters

//todo multi part returns




// source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737591%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

using namespace std;

//string socketClient(string input);

char address[] = "127.0.0.1";


Socket mySocket( *address);

struct Data
{
    bool ready = false;
    string params = "";
    string result = "";
};

unordered_map<long int, Data> tickets;
mutex mtx;
atomic<bool> worker_working(false);
long int id = 0;// global ticket id 
long int cur_id = 0; // current ticket id 


extern "C"
{
    __declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);
}

void worker()
{
    while (worker_working = id > cur_id) // next ticket exists? 
    {
        string output;
        mtx.lock();
        Data ticket = tickets[++cur_id];// copy ticket 
        mtx.unlock();

        string input = ticket.params; // get input 
        //string output = "output: " + input; // process input 
        //Sleep(10); //sleep for 0.01 sec (FOR TESTING PURPOSES ONLY) 
        switch (mySocket.getStatus()){

        case -1:
            mySocket.Connect();


        case 0:
            output = mySocket.SendRecieve(input);
            break;

        case 1:
            output = mySocket.getStatusMsg();
                if (output == ""){
                    output = "an uknown eror occured";
                }
            break;


        };
        //string output = socketClient(input);
        //code here
        //output = output +"\n"+ "\0";

        ticket.result = output; // prepare result 
        ticket.ready = true; // notify about result 
        mtx.lock(); tickets[cur_id] = ticket; // copy back the result 
        mtx.unlock();
    }
}


void __stdcall RVExtension(char *output, int outputSize, const char *function)
{
    if (!strncmp(function, "r:", 2)) // detect checking for result 
    {
        long int num = atol(&function[2]); // ticket number or 0
        if (tickets.find(num) != tickets.end()) // ticket exists 
        {
            mtx.lock();
            if (tickets[num].ready) // result is ready 
            {
                strncpy_s(output, outputSize, tickets[num].result.c_str(), _TRUNCATE); // result 
                tickets.erase(num); // get rid of the read ticket 
                mtx.unlock();
                return;
            }
            mtx.unlock();
            strncpy_s(output, outputSize, "WAIT", _TRUNCATE);// result is not ready 
            return;
        }
        strncpy_s(output, outputSize, "EMPTY", _TRUNCATE); // no such ticket 
    }
    else if (!strncmp(function, "s:", 2)) // detect ticket submission 
    {
        Data data;
        data.params = string(&function[2]); // extract params 
        mtx.lock(); tickets.insert(pair<long int, Data>(++id, data)); // add ticket to the queue 
        mtx.unlock();
        if (!worker_working) // if worker thread is finished, start another one 
        {
            worker_working = true;
            thread worker(worker);
            worker.detach(); // start parallel process 
        }
        strncpy_s(output, outputSize, to_string(id).c_str(), _TRUNCATE); // ticket number 
    }
    else
    {
        strncpy_s(output, outputSize, "INVALID COMMAND", _TRUNCATE); // other input 
    }
}

My experience is mainly with python, and PHP. this is my first proper project using c++ and VS2013.

L Selter
  • 352
  • 3
  • 21

2 Answers2

4

The error is not a compiler error, it is a linker error. There is a difference between the two, and knowing the difference will make you more aware of the issue at hand.

The linker error states that it cannot find the Socket::Socket(void) function implemented. Looking at your code, this seems that the implementation of the no-argument (default) constructor for Socket is missing.

Your code compiled without issues, since the compiler doesn't care whether the function(s) you're calling really do exist. As long as there is a declaration of the function (just as you have in your code), or the function body is located before the call of the function, the compiler says "ok, no problem".

After successful compilation, the linker now actually tries to look for the functions that your code is calling. If it can't find the function, either in the other object modules or libraries, then the linker gives you the "unresolved external" error. If you get those errors, read the error message carefully, as the error is stating what function(s) is (are) being called, but cannot be found.

That gobbledy-gook that looks like the linker is going nuts -- that is just name mangling and not the concern for this type of error. The important part of the message is the class and function name, along with the parameters (which in this case is void, meaning no arguments).

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
0

I think you are just missing the implementation of the function Socket(). Implement Socket() in your .cpp and everything should work.

Corb3nik
  • 1,177
  • 7
  • 26