Вызов функций WinSock с использованием LoadLibrary и GetProcAddress
В основном у меня есть файл заголовка, как это:
#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
и тогда я делаю что-то вроде этого:
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;
Однако, когда я вызываю эту функцию (строка с (*start)(test, &wsdata)), я получаю это сообщение об ошибке:
Необработанное исключение в 0x7868146a в sockets.exe: 0xC0000005: нарушение прав доступа.
Я попытался изменить соглашение о вызовах (__cdecl, WINAPI, WSAAPI), но оно всегда заканчивается одним и тем же сообщением об ошибке.
3 ответа
Решено! Спасибо за вашу помощь. Чтобы исправить это, я просто изменил typedef следующим образом:
typedef int (WSAAPI SocketStartup)( IN WORD wVersionRequested, OUT LPWSADATA lpWSAData );
В основном я копирую и вставляю из Winsock2.h:P
Принимая во внимание ваш ответ Ремусу Русану, если причина, по которой вы хотите это сделать, заключается только в портировании между различными платформами, абстрагирование на уровне импорта - это неправильный способ сделать то, что вы хотите. Например, коды ошибок, которые будут возвращать схожие функции сокетов на разных платформах, различаются (не только по их идентификатору / номеру, но и по значению и доступности).
Я делал это раньше и использовал короткие функции-оболочки для функций сокетов, специфичных для платформы (или нескольких функций, где это необходимо), которые переводили сообщения об ошибках и т. Д., Чтобы они были единообразными WRT для моего приложения; У меня был отдельный файл / реализация для каждой платформы. Это сработало хорошо.
Учитывая определение препроцессора, которое вы используете и / или не используете, каково значение "WINAPI
"Когда вы его компилируете? Я спрашиваю, потому что windef.h
содержит странные вещи, как...
#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
В ваших определениях typedef попробуйте это с помощью __stdcall
вместо WINAPI
,
редактировать
Когда я запускаю следующий код на моей машине, он не падает, и вызов socketStartup возвращает 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;
}
Это использует Visual C++ 2008 со следующей командной строкой компилятора:
/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt