views:

1030

answers:

3

Basically I have a header file like this:

#if WIN32
typedef DWORD (WSAAPI *SocketStartup) (WORD wVersionRequested, LPWSADATA lpWSAData);
typedef SOCKET (WINAPI *MakeSocket)(IN int af,    IN int type,    IN int protocol,    IN LPWSAPROTOCOL_INFOW lpProtocolInfo,    IN GROUP g,    IN DWORD dwFlags    );
typedef DWORD (WINAPI *SocketSendFunc) (IN SOCKET s,__in_bcount(len) const char FAR * buf, IN int len,IN int flags);
typedef DWORD (WINAPI *GetLastSocketErrorFunc)();
typedef DWORD (WINAPI *ShutdownSocketFunc)(SOCKET hSocket, int how);
typedef DWORD (WINAPI *CloseSocketFunc)(SOCKET hSocket);
#endif

and then I do something like this:

    SocketStartup* start = (SocketStartup*)GetProcAddress(socketLib,"WSAStartup");
    getLastSocketError = (GetLastSocketErrorFunc*)GetProcAddress(socketLib,"WSAGetLastError");
    closeSocket = (CloseSocketFunc*)GetProcAddress(socketLib,"closesocket");
    shutdownSocket = (ShutdownSocketFunc*) GetProcAddress(socketLib,"shutdown");
    socketSend = (SocketSendFunc*) GetProcAddress(socketLib, "send");
    if(start == 0 || getLastSocketError == 0 || closeSocket == 0 || shutdownSocket == 0
     || socketSend == 0)
    {
     printf("[!] Failed to find entry points in Ws2_32.dll. Error Code: %d\n", GetLastError());
     CloseLibraries();
     ErrorExit();
    }
    WSADATA wsdata;

    //ZeroMemory(&wsdata,sizeof(wsdata));
    printf("error: %d\n", GetLastError());
    WORD test = MAKEWORD(1,1);
    int result = (*start)(test, &wsdata);
    return result == 0;

However, when I call this function (the line with (*start)(test, &wsdata)) I get this error message:

Unhandled exception at 0x7868146a in sockets.exe: 0xC0000005: Access violation.

I tried changing the calling convention (__cdecl, WINAPI, WSAAPI) but it always ends with the same error message.

A: 

Given the preprocessor definition which you are and/or are not using, what is the value of "WINAPI" when you compile it? I'm asking because windef.h contains odd things like ...

#ifdef _MAC
#define CALLBACK    PASCAL
#define WINAPI      CDECL
#define WINAPIV     CDECL
#define APIENTRY    WINAPI
#define APIPRIVATE  CDECL
#ifdef _68K_
#define PASCAL      __pascal
#else
#define PASCAL
#endif
#elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define CALLBACK    __stdcall
#define WINAPI      __stdcall
#define WINAPIV     __cdecl
#define APIENTRY    WINAPI
#define APIPRIVATE  __stdcall
#define PASCAL      __stdcall
#else
#define CALLBACK
#define WINAPI
#define WINAPIV
#define APIENTRY    WINAPI
#define APIPRIVATE
#define PASCAL      pascal
#endif

In your typedef definitions, try it with using __stdcall instead of WINAPI.


Edit

When I run the following code on my machine, it doesn't crash, and the socketStartup call returns 0:

#include "windows.h"

typedef DWORD (PASCAL FAR *SocketStartup) (WORD wVersionRequested, LPWSADATA lpWSAData);

int main(int argc, char* argv[])
{
    HMODULE hModule = LoadLibrary("wsock32.dll");
    SocketStartup socketStartup = (SocketStartup)GetProcAddress(hModule, "WSAStartup");
    WSADATA wsdata;

    WORD test = MAKEWORD(1,1);
    int result = (*socketStartup)(test, &wsdata);
    return result == 0;
    return 0;
}

That's using Visual C++ 2008, with the following compiler command-line:

/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt
ChrisW
WINAPI = __stdcallWSAAPI = PASCAL FARI tried using __stdcall and PASCAL FAR in place of each and it still doesn't work =[.
Chris T
I've tried it on my machine, and edited my answer to show my results. PASCAL evaluates to __stdcall.
ChrisW
+1  A: 

Taking into account your reply to Remus Rusanu, if the reason you're wanting to do this is only to port between different platforms, abstracting at the import level is the wrong way to do what you want. For example, the error codes that the similar looking socket functions on different platforms will return, vary (not just in their id/number, but in meaning, and availability).

I've done this before, and went with having short wrapper functions around the platform specific socket functions (or multiple functions where necessary), that translated error messages etc so that they were uniform WRT to my application; I had a separate file/implementation for each platform. It worked well.

irrraze
Thanks for your suggestion but I'd still like to get this working because the main objective for this project was to learn how to do this sort of thing in a different way and I've never done much with dynamically calling functions from dlls
Chris T
I'm going to use this type of system in the future
Chris T
A: 

Solved! Thank you all for your help. To fix it I just changed the typedef as follows:

typedef int (WSAAPI SocketStartup)(    IN WORD wVersionRequested,    OUT LPWSADATA lpWSAData    );

Basically I copy and pasted from Winsock2.h :P

Chris T
I don't see a significant difference between what you're doing now and what you were doing before.
ChrisW
WSAAPI *SocketStartup changed to WSAAPI SocketStartup
Chris T
I still don't get it; it worked for me when I tried it using "`typedef DWORD (PASCAL FAR *SocketStartup) (WORD wVersionRequested, etc.`".
ChrisW