Chamando funções do Winsock usando LoadLibrary e GetProcAddress
-
18-09-2019 - |
Pergunta
Basicamente, eu tenho um arquivo de cabeçalho como este:
#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
e então eu fazer algo parecido com isto:
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;
No entanto, quando eu chamar esta função (a linha com (* start) (teste, e wsdata)) eu recebo essa mensagem de erro:
Excepção em 0x7868146a em SOCKETS.EXE: 0xC0000005: Acesso violação.
Eu tentei mudar a convenção de chamada (__cdecl, WinAPI, WSAAPI), mas ele sempre termina com a mesma mensagem de erro.
Solução 2
resolvido! Obrigado a todos por sua ajuda. Para corrigi-lo Eu só mudou o typedef da seguinte forma:
typedef int (WSAAPI SocketStartup)( IN WORD wVersionRequested, OUT LPWSADATA lpWSAData );
Basicamente eu copiar e colado de Winsock2.h: P
Outras dicas
Tendo em conta a sua resposta a Remus Rusanu, se a razão que você está querendo fazer isso é apenas para a porta entre diferentes plataformas, abstraindo ao nível de importação é a maneira errada de fazer o que quiser. Por exemplo, os códigos de erro que as funções de soquete de aparência semelhante em diferentes plataformas vai voltar, variar (e não apenas em seu id / número, mas em significado e disponibilidade).
Eu tenho feito isso antes, e passou a ter funções curtas invólucro em torno do soquete funções plataforma específica (ou várias funções quando necessário), que mensagens de erro traduzido etc, para que eles eram WRT uniforme ao meu pedido; Eu tinha um arquivo / implementação separada para cada plataforma. Funcionou bem.
Dada a definição de pré-processamento que você é e / ou não estiver usando, o que é o valor de "WINAPI
" quando você compilá-lo? Estou perguntando porque windef.h
contém coisas estranhas como ...
#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
Em suas definições typedef, experimentá-lo com o uso de __stdcall
vez de WINAPI
.
Editar
Quando eu execute o seguinte código na minha máquina, ele não falha, e as chamadas socketStartup retorna 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;
}
Isso é usando o Visual C ++ 2008, com a seguinte linha de comando do compilador:
/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt