我尝试使用Microsoft SDK库从IcmpSendEcho
加载iphlpapi.dll
而不是。我在Windows 7 x64上使用GCC 4.8.1(win32)。我这样试过:
我汇总了一个展示我问题的小例子:
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
typedef struct {
union {
struct {
u_char s_b1,s_b2,s_b3,s_b4;
} S_un_b;
struct {
u_short s_w1,s_w2;
} S_un_w;
u_long S_addr;
} S_un;
} IPAddr;
#define IP_FLAG_REVERSE 0x01
#define IP_FLAG_DF 0x02
typedef struct {
UCHAR Ttl;
UCHAR Tos;
UCHAR Flags;
UCHAR OptionsSize;
PUCHAR OptionsData;
} IP_OPTION_INFORMATION;
typedef struct {
IPAddr Address;
ULONG Status;
ULONG RoundTripTime;
USHORT DataSize;
USHORT Reserved;
PVOID Data;
IP_OPTION_INFORMATION Options;
} ICMP_ECHO_REPLY;
typedef HANDLE (*IcmpCreateFile_t)();
typedef BOOL (*IcmpCloseHandle_t)(
HANDLE IcmpHandle // _In_ HANDLE IcmpHandle
);
typedef DWORD (*IcmpSendEcho_t)(
HANDLE IcmpHandle, // _In_ HANDLE IcmpHandle,
IPAddr dst, // _In_ IPAddr DestinationAddress,
void * RequestData, // _In_ LPVOID RequestData,
WORD RequestSize, // _In_ WORD RequestSize,
IP_OPTION_INFORMATION * RequestOptions, // _In_opt_ PIP_OPTION_INFORMATION RequestOptions,
void * ReplyBuffer, // _Out_ LPVOID ReplyBuffer,
DWORD ReplySize, // _In_ DWORD ReplySize,
DWORD Timeout // _In_ DWORD Timeout
);
HINSTANCE hIPHLPAPI = NULL;
IcmpCreateFile_t IcmpCreateFile = NULL;
IcmpCloseHandle_t IcmpCloseHandle = NULL;
IcmpSendEcho_t IcmpSendEcho = NULL;
HANDLE hIcmpFile;
int icmp_init() {
hIPHLPAPI = LoadLibrary("iphlpapi.dll");
if(hIPHLPAPI == NULL) return 0;
IcmpCreateFile = (IcmpCreateFile_t) GetProcAddress(hIPHLPAPI, "IcmpCreateFile");
if(IcmpCreateFile == NULL) return 0;
IcmpCloseHandle = (IcmpCloseHandle_t) GetProcAddress(hIPHLPAPI, "IcmpCloseHandle");
if(IcmpCloseHandle == NULL) return 0;
IcmpSendEcho = (IcmpSendEcho_t) GetProcAddress(hIPHLPAPI, "IcmpSendEcho");
if(IcmpSendEcho == NULL) return 0;
hIcmpFile = IcmpCreateFile();
if(!hIcmpFile) return 0;
return 1;
}
int icmp_ping(uint32_t ip) {
// Echo request data
int dataSize = 32;
void * data = malloc(dataSize);
// Reply buffer
int replySize = sizeof(ICMP_ECHO_REPLY) + 128;
void * replyBuffer = malloc(replySize);
if(replyBuffer == NULL) return 0;
// Send echo request and wait for reply
IPAddr dst;
dst.S_un.S_addr = ip;
printf("Calling IcmpSendEcho\n");
DWORD dwRetVal = IcmpSendEcho(hIcmpFile, dst, data, dataSize, NULL, replyBuffer, replySize, 1000);
if(dwRetVal == 0) return 0;
ICMP_ECHO_REPLY *echoreply = (ICMP_ECHO_REPLY *) replyBuffer;
printf("Status = %ld\n", echoreply->Status);
free(replyBuffer);
return 0;
}
int icmp_free() {
FreeLibrary(hIPHLPAPI);
return 1;
}
int main(int argc, char *argv[]) {
if(icmp_init()) {
int pret = icmp_ping(2915201282 /* google.com */);
printf("icmp_ping returned %d\n", pret);
icmp_free();
}
}
我使用gcc -o icmp_test.exe icmpt_test.c
编译此示例。它打印“Calling IcmpSendEcho”并崩溃(见下文)。
这不是“真正的”代码,但它以同样的方式失败。对IcmpCreateFile
的调用成功,但调用IcmpSendEcho
会使程序崩溃并使Windows显示“...已停止工作”。
我认为问题可能与错误的指针有关,但我找不到问题。
答案 0 :(得分:4)
使用GetProcAddress
同步链接库时,需要确保匹配签名和调用约定。虽然签名通常很容易纠正,但很容易忘记考虑calling convention。
Windows中的系统模块始终使用__stdcall
,这也可以通过WINAPI
预处理器宏获得。要修复代码以便编译器为函数调用生成适当的指令,您需要更新以下函数指针类型以包含适当的调用约定:
typedef HANDLE (WINAPI* IcmpCreateFile_t)();
typedef BOOL (WINAPI* IcmpCloseHandle_t)(
HANDLE IcmpHandle // _In_ HANDLE IcmpHandle
);
typedef DWORD (WINAPI* IcmpSendEcho_t)(
HANDLE IcmpHandle, // _In_ HANDLE IcmpHandle,
IPAddr dst, // _In_ IPAddr DestinationAddress,
void * RequestData, // _In_ LPVOID RequestData,
WORD RequestSize, // _In_ WORD RequestSize,
IP_OPTION_INFORMATION * RequestOptions, // _In_opt_ PIP_OPTION_INFORMATION
RequestOptions,
void * ReplyBuffer, // _Out_ LPVOID ReplyBuffer,
DWORD ReplySize, // _In_ DWORD ReplySize,
DWORD Timeout // _In_ DWORD Timeout
);