• c++/VS XP系统 无法定位程序输入点WSAPoll于动态链接库ws2_32.dll解决方案


    项目情况:

    调用第三方网络库(hv库),在win7/8/10等系统都运行正常,在XP系统提示“ 无法定位程序输入点WSAPoll于动态链接库ws2_32.dll”

    产生原因:

    第三方网络库(hv库)使用到了wsapoll,inet_pton,inet_ntop等函数,这些函数是定义在系统库ws2_32.dll里面的,而XP系统的ws2_32.dll库并没有这些函数。这些函数在 Windows Vista 及更高版本上才被定义。

    解决思路(可以直接看思路3):

    思路1:最简单,更新系统呗,不用XP;等于没解决

    思路2: 换系统库呗。我把win7以上的ws2_32.dll拷过去还不行?

    ①拷贝到C:\Windows\System32; 可以吗?不行,这里的库只有安全模式可以更改,总不能每台机器都整;

    ②拷贝到程序当前目录可以吗?不行。看下图,程序的的确确找到了WS2_32.DLL,但是WS2_32.DLL又依赖系统库MSVCRT.DLL,但是XP系统的MSVCRT.DLL,又缺少了win 7 WS2_32.DLL要调用的函数,所以就这样层层报错。我试过把win7的MSVCRT.DLL和依赖库全部拷过来,xp系统也会找C:\Windows\System32上面的MSVCRT.DLL,即使修改环境变量也不起效。

    思路3: 改第三方网络库(hv库)的源码。不是报几个函数在XP的WS2_32.DLL没定义吗,那我自己写还不行吗?

    ①WSAPOLL函数,我参考thrift库重写(名字要修改不要重定义):

    thrift库:​​​​​​Index of /dist/thrift     我用的是0.12.0

    1. typedef struct timeval2
    2. {
    3. double tv_sec; /* seconds */
    4. double tv_usec; /* microseconds */
    5. }timeval;
    6. # define THRIFT_POLLIN 0x0300
    7. # define THRIFT_POLLOUT 0x0010
    8. /// 需要屏蔽此行
    9. int thrift_poll1(WSAPOLLFD *fdArray, ULONG nfds, INT timeout)
    10. {
    11. fd_set read_fds, write_fds;
    12. fd_set* read_fds_ptr = NULL;
    13. fd_set* write_fds_ptr = NULL;
    14. FD_ZERO(&read_fds);
    15. FD_ZERO(&write_fds);
    16. for (ULONG i = 0; i
    17. //Read (in) socket
    18. if ((fdArray[i].events & THRIFT_POLLIN) == THRIFT_POLLIN) {
    19. read_fds_ptr = &read_fds;
    20. FD_SET(fdArray[i].fd, &read_fds);
    21. }
    22. //Write (out) socket
    23. if ((fdArray[i].events & THRIFT_POLLOUT) == THRIFT_POLLOUT) {
    24. write_fds_ptr = &write_fds;
    25. FD_SET(fdArray[i].fd, &write_fds);
    26. }
    27. }
    28. timeval time_out;
    29. timeval* time_out_ptr = NULL;
    30. if (timeout >= 0) {
    31. timeval time_out = { timeout / 1000, (timeout % 1000) * 1000 };
    32. time_out_ptr = &time_out;
    33. }
    34. else { //to avoid compiler warnings
    35. (void)time_out;
    36. (void)timeout;
    37. }
    38. int sktready = select(1, read_fds_ptr, write_fds_ptr, NULL, time_out_ptr);
    39. if (sktready > 0) {
    40. for (ULONG i = 0; i
    41. fdArray[i].revents = 0;
    42. if (FD_ISSET(fdArray[i].fd, &read_fds))
    43. fdArray[i].revents |= THRIFT_POLLIN;
    44. if (FD_ISSET(fdArray[i].fd, &write_fds))
    45. fdArray[i].revents |= THRIFT_POLLOUT;
    46. }
    47. }
    48. return sktready;
    49. }
    50. //WSAPOLL函数
    51. int WINAPI myWSAPoll(WSAPOLLFD *wfds, ULONG count, int timeout)
    52. {
    53. return thrift_poll1(wfds, count, timeout);
    54. }

     ②inet_pton和inet_ntop,我参考glibc库重写(名字要修改不要重定义):

     glibc库:Index of /pub/gnu/glibc     我用的是glibc-2.36

    inet_pton:

    1. #define NS_INADDRSZ 4 /*%< IPv4 T_A */
    2. #define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */
    3. #define NS_INT16SZ 2 /*%< #/bytes of data in a uint16_t */
    4. static int inet_pton4(const char *src, const char *end, unsigned char *dst)
    5. {
    6. int saw_digit; // 每个八位组是否遇到数字标记,新的八位组将会清除标记
    7. int octets; // 八位组的个数,ip地址合法,则为4个
    8. int ch; // 遍历字符串,每次获得的字符
    9. // NS_INADDRSZ长度是4个字节, 宏定义在nameser.h中
    10. // 注意tmp不是字符串,仅仅是用来存放4个字节的数据,无'\0'
    11. unsigned char tmp[NS_INADDRSZ];
    12. unsigned char *tp; // tp指的是八位组
    13. saw_digit = 0;
    14. octets = 0;
    15. *(tp = tmp) = 0; // *tp = 0;初始化必须为0,计算数值的时候会有依赖
    16. // 本函数实际上是转换成网络序的,所以方向是src -> end
    17. // 如果仅仅转换成二进制,方向是end -> src
    18. while (src < end)
    19. {
    20. ch = *src++; // 得到获得的ASCII值,src指向下一个字符
    21. if (ch >= '0' && ch <= '9')
    22. {
    23. // 八位组迭代,比如192.168.8.217
    24. // 以192为例:
    25. // 0 -> 0 * 10 + 1 = 1 -> 1 * 10 + 9 = 19 -> 19 * 10 + 2 = 192
    26. // 在将192赋值到tmp的第一个字节上(第一个八位组)
    27. unsigned int new = *tp * 10 + (ch - '0');
    28. // 八位组中不能以0开头,比如192.168.08.217是错误的
    29. if (saw_digit && *tp == 0)
    30. return 0;
    31. // 某一个八位组值不能超过255
    32. if (new > 255)
    33. return 0;
    34. // 八位组赋值
    35. *tp = new;
    36. // 一般是在遇到'.'的时候,(! saw_digit)为0
    37. // 而在'.'之后的第一个数字置为1
    38. // 统计八位组的数目,由于在运行中,所以值不得超过4
    39. if (!saw_digit)
    40. {
    41. if (++octets > 4)
    42. return 0;
    43. saw_digit = 1;
    44. }
    45. }
    46. else if (ch == '.' && saw_digit)
    47. {
    48. if (octets == 4)
    49. return 0;
    50. // 下一个八位组赋值,必须为0,方面迭代
    51. // saw_digit标记为未遇到数值
    52. *++tp = 0;
    53. saw_digit = 0;
    54. }
    55. else
    56. return 0; // 其他字符,直接返回错误
    57. }
    58. if (octets < 4)
    59. return 0;
    60. memcpy(dst, tmp, NS_INADDRSZ);
    61. return 1;
    62. }
    63. static int hex_digit_value(char ch)
    64. {
    65. if ('0' <= ch && ch <= '9')
    66. return ch - '0';
    67. if ('a' <= ch && ch <= 'f')
    68. return ch - 'a' + 10;
    69. if ('A' <= ch && ch <= 'F')
    70. return ch - 'A' + 10;
    71. return -1;
    72. }
    73. static int inet_pton6(const char *src, const char *src_endp, unsigned char *dst)
    74. {
    75. unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
    76. const char *curtok;
    77. int ch;
    78. size_t xdigits_seen; /* Number of hex digits since colon. */
    79. unsigned int val;
    80. tp = memset(tmp, '\0', NS_IN6ADDRSZ);
    81. endp = tp + NS_IN6ADDRSZ;
    82. colonp = NULL;
    83. /* Leading :: requires some special handling. */
    84. if (src == src_endp)
    85. return 0;
    86. if (*src == ':')
    87. {
    88. ++src;
    89. if (src == src_endp || *src != ':')
    90. return 0;
    91. }
    92. curtok = src;
    93. xdigits_seen = 0;
    94. val = 0;
    95. while (src < src_endp)
    96. {
    97. ch = *src++;
    98. int digit = hex_digit_value(ch);
    99. if (digit >= 0)
    100. {
    101. if (xdigits_seen == 4)
    102. return 0;
    103. val <<= 4;
    104. val |= digit;
    105. if (val > 0xffff)
    106. return 0;
    107. ++xdigits_seen;
    108. continue;
    109. }
    110. if (ch == ':')
    111. {
    112. curtok = src;
    113. if (xdigits_seen == 0)
    114. {
    115. if (colonp)
    116. return 0;
    117. colonp = tp;
    118. continue;
    119. }
    120. else if (src == src_endp)
    121. return 0;
    122. if (tp + NS_INT16SZ > endp)
    123. return 0;
    124. *tp++ = (unsigned char)(val >> 8) & 0xff;
    125. *tp++ = (unsigned char)val & 0xff;
    126. xdigits_seen = 0;
    127. val = 0;
    128. continue;
    129. }
    130. if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
    131. && inet_pton4(curtok, src_endp, tp) > 0)
    132. {
    133. tp += NS_INADDRSZ;
    134. xdigits_seen = 0;
    135. break; /* '\0' was seen by inet_pton4. */
    136. }
    137. return 0;
    138. }
    139. if (xdigits_seen > 0)
    140. {
    141. if (tp + NS_INT16SZ > endp)
    142. return 0;
    143. *tp++ = (unsigned char)(val >> 8) & 0xff;
    144. *tp++ = (unsigned char)val & 0xff;
    145. }
    146. if (colonp != NULL)
    147. {
    148. /* Replace :: with zeros. */
    149. if (tp == endp)
    150. /* :: would expand to a zero-width field. */
    151. return 0;
    152. size_t n = tp - colonp;
    153. memmove(endp - n, colonp, n);
    154. memset(colonp, 0, endp - n - colonp);
    155. tp = endp;
    156. }
    157. if (tp != endp)
    158. return 0;
    159. memcpy(dst, tmp, NS_IN6ADDRSZ);
    160. return 1;
    161. }
    162. int __inet_pton_length(int af, const char *src, size_t srclen, void *dst)
    163. {
    164. switch (af)
    165. {
    166. case AF_INET:
    167. return inet_pton4(src, src + srclen, dst);
    168. case AF_INET6:
    169. return inet_pton6(src, src + srclen, dst);
    170. default:
    171. //__set_errno(EAFNOSUPPORT);
    172. return -1;
    173. }
    174. }
    175. //inet_pton
    176. int __inet_pton(int af, const char *src, void *dst)
    177. {
    178. return __inet_pton_length(af, src, strlen(src), dst);
    179. }

    inet_ntop:

    1. #ifdef SPRINTF_CHAR
    2. # define SPRINTF(x) strlen(sprintf/**/x)
    3. #else
    4. # define SPRINTF(x) ((size_t)sprintf x)
    5. #endif
    6. static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size)
    7. {
    8. static const char fmt[] = "%u.%u.%u.%u";
    9. char tmp[sizeof "255.255.255.255"];
    10. if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
    11. //__set_errno(ENOSPC);
    12. return (NULL);
    13. }
    14. return strcpy(dst, tmp);
    15. }
    16. /* const char *
    17. * inet_ntop6(src, dst, size)
    18. * convert IPv6 binary address into presentation (printable) format
    19. * author:
    20. * Paul Vixie, 1996.
    21. */
    22. static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size)
    23. {
    24. /*
    25. * Note that int32_t and int16_t need only be "at least" large enough
    26. * to contain a value of the specified size. On some systems, like
    27. * Crays, there is no such thing as an integer variable with 16 bits.
    28. * Keep this in mind if you think this function should have been coded
    29. * to use pointer overlays. All the world's not a VAX.
    30. */
    31. char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
    32. struct { int base, len; } best, cur;
    33. u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
    34. int i;
    35. /*
    36. * Preprocess:
    37. * Copy the input (bytewise) array into a wordwise array.
    38. * Find the longest run of 0x00's in src[] for :: shorthanding.
    39. */
    40. memset(words, '\0', sizeof words);
    41. for (i = 0; i < NS_IN6ADDRSZ; i += 2)
    42. words[i / 2] = (src[i] << 8) | src[i + 1];
    43. best.base = -1;
    44. cur.base = -1;
    45. best.len = 0;
    46. cur.len = 0;
    47. for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
    48. if (words[i] == 0) {
    49. if (cur.base == -1)
    50. cur.base = i, cur.len = 1;
    51. else
    52. cur.len++;
    53. }
    54. else {
    55. if (cur.base != -1) {
    56. if (best.base == -1 || cur.len > best.len)
    57. best = cur;
    58. cur.base = -1;
    59. }
    60. }
    61. }
    62. if (cur.base != -1) {
    63. if (best.base == -1 || cur.len > best.len)
    64. best = cur;
    65. }
    66. if (best.base != -1 && best.len < 2)
    67. best.base = -1;
    68. /*
    69. * Format the result.
    70. */
    71. tp = tmp;
    72. for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
    73. /* Are we inside the best run of 0x00's? */
    74. if (best.base != -1 && i >= best.base &&
    75. i < (best.base + best.len)) {
    76. if (i == best.base)
    77. *tp++ = ':';
    78. continue;
    79. }
    80. /* Are we following an initial run of 0x00s or any real hex? */
    81. if (i != 0)
    82. *tp++ = ':';
    83. /* Is this address an encapsulated IPv4? */
    84. if (i == 6 && best.base == 0 &&
    85. (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
    86. if (!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
    87. return (NULL);
    88. tp += strlen(tp);
    89. break;
    90. }
    91. tp += SPRINTF((tp, "%x", words[i]));
    92. }
    93. /* Was it a trailing run of 0x00's? */
    94. if (best.base != -1 && (best.base + best.len) ==
    95. (NS_IN6ADDRSZ / NS_INT16SZ))
    96. *tp++ = ':';
    97. *tp++ = '\0';
    98. /*
    99. * Check for overflow, copy, and we're done.
    100. */
    101. if ((socklen_t)(tp - tmp) > size) {
    102. //__set_errno(ENOSPC);
    103. return (NULL);
    104. }
    105. return strcpy(dst, tmp);
    106. }
    107. //inet_ntop
    108. const char *inet_ntop1(int af, const void *src, char *dst, socklen_t size)
    109. {
    110. switch (af) {
    111. case AF_INET:
    112. return (inet_ntop4(src, dst, size));
    113. case AF_INET6:
    114. return (inet_ntop6(src, dst, size));
    115. default:
    116. //__set_errno(EAFNOSUPPORT);
    117. return (NULL);
    118. }
    119. /* NOTREACHED */
    120. }

  • 相关阅读:
    JS-闭包的用法
    创建vue3项目并引用elementui
    基于JPBC的无证书聚合签名方案实现
    认识 URL
    测试架构需要具备哪些能力
    (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
    【5w字】SpringBoot源码分析
    usb 命名乱的一批,怎么破
    视频转二维码简单技巧,适用多种视频格式
    Java内存模型之JMM
  • 原文地址:https://blog.csdn.net/yaojinjian1995/article/details/127926276