استدعاء وظائف Winsock باستخدام LoadLibrary و GetProcaddress
-
18-09-2019 - |
سؤال
في الأساس لدي ملف رأس مثل هذا:
#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;
ومع ذلك، عندما أسمي هذه الوظيفة (الخط مع (* ابدأ) (اختبار، & Wsdata)) أحصل على رسالة الخطأ هذه:
استثناء غير معالج في 0x7868146A في Sockets.exe: 0xc0000005: انتهاك الوصول.
حاولت تغيير اتفاقية الاتصال (__CDECL، وينتاب، WSAAPI) ولكنها تنتهي دائما مع نفس رسالة الخطأ.
المحلول 2
تم حلها! شكرا لكم جميعا لمساعدتكم. لإصلاحه لقد غيرت Typedef كما يلي:
typedef int (WSAAPI SocketStartup)( IN WORD wVersionRequested, OUT LPWSADATA lpWSAData );
أساسا أنا نسخ ولصق من Winsock2.h: P
نصائح أخرى
مع الأخذ في الاعتبار ردكم على Remus Rusanu، إذا كان السبب في أنك تريد القيام بذلك هو فقط للمنفذ بين المنصات المختلفة، فإن التجريد على مستوى الاستيراد هو الطريقة الخاطئة للقيام بما تريد. على سبيل المثال، فإن رموز الخطأ التي ستعود وظائف مأخذ التوصيل المطلقة على منصات مختلفة، تختلف (ليس فقط في معرف / رقمها، ولكن في المعنى، والتوافر).
لقد قمت بذلك من قبل، وذهبت مع وجود وظائف غلاف قصيرة حول وظائف المقبس المحددة من النظام الأساسي (أو وظائف متعددة عند الضرورة)، والتي ترجمت رسائل الخطأ وما إلى ذلك حتى تكون موحدة WRT على طلبي؛ كان لدي ملف / تنفيذ منفصل لكل منصة. عملت بشكل جيد.
بالنظر إلى تعريف Preprocessor الذي أنت و / أو لا تستخدم، فما هي قيمة "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
.
يحرر
عندما أقوم بتشغيل التعليمات البرمجية التالية على جهازي، فإنه لا يتعطل، وإرجاع مكالمة SocketStartuptup 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