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

news2025/8/11 12:13:10

项目情况:

调用第三方网络库(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

typedef struct timeval2
{
	double      tv_sec;     /* seconds */
	double tv_usec;    /* microseconds */
}timeval;


#  define THRIFT_POLLIN  0x0300
#  define THRIFT_POLLOUT 0x0010
/// 需要屏蔽此行
int thrift_poll1(WSAPOLLFD *fdArray, ULONG nfds, INT timeout)
{
	fd_set read_fds, write_fds;
	fd_set* read_fds_ptr = NULL;
	fd_set* write_fds_ptr = NULL;

	FD_ZERO(&read_fds);
	FD_ZERO(&write_fds);

	for (ULONG i = 0; i<nfds; i++) {
		//Read (in) socket
		if ((fdArray[i].events & THRIFT_POLLIN) == THRIFT_POLLIN) {
			read_fds_ptr = &read_fds;
			FD_SET(fdArray[i].fd, &read_fds);
		}
		//Write (out) socket
		else if ((fdArray[i].events & THRIFT_POLLOUT) == THRIFT_POLLOUT) {
			write_fds_ptr = &write_fds;
			FD_SET(fdArray[i].fd, &write_fds);
		}
	}

	timeval time_out;
	timeval* time_out_ptr = NULL;
	if (timeout >= 0) {
		timeval time_out = { timeout / 1000, (timeout % 1000) * 1000 };
		time_out_ptr = &time_out;
	}
	else { //to avoid compiler warnings
		(void)time_out;
		(void)timeout;
	}

	int sktready = select(1, read_fds_ptr, write_fds_ptr, NULL, time_out_ptr);
	if (sktready > 0) {
		for (ULONG i = 0; i<nfds; i++) {
			fdArray[i].revents = 0;
			if (FD_ISSET(fdArray[i].fd, &read_fds))
				fdArray[i].revents |= THRIFT_POLLIN;
			if (FD_ISSET(fdArray[i].fd, &write_fds))
				fdArray[i].revents |= THRIFT_POLLOUT;
		}
	}
	return sktready;
}

//WSAPOLL函数
int WINAPI myWSAPoll(WSAPOLLFD *wfds, ULONG count, int timeout)
{
	return thrift_poll1(wfds, count, timeout);

}

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

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

inet_pton:


#define NS_INADDRSZ	4	/*%< IPv4 T_A */
#define NS_IN6ADDRSZ	16	/*%< IPv6 T_AAAA */
#define NS_INT16SZ	2	/*%< #/bytes of data in a uint16_t */

static int inet_pton4(const char *src, const char *end, unsigned char *dst)
{
	int saw_digit; // 每个八位组是否遇到数字标记,新的八位组将会清除标记
	int octets;     // 八位组的个数,ip地址合法,则为4个
	int ch;         // 遍历字符串,每次获得的字符
					// NS_INADDRSZ长度是4个字节, 宏定义在nameser.h中
					// 注意tmp不是字符串,仅仅是用来存放4个字节的数据,无'\0'
	unsigned char tmp[NS_INADDRSZ];
	unsigned char *tp;      // tp指的是八位组

	saw_digit = 0;
	octets = 0;
	*(tp = tmp) = 0; // *tp = 0;初始化必须为0,计算数值的时候会有依赖

					 // 本函数实际上是转换成网络序的,所以方向是src -> end
					 // 如果仅仅转换成二进制,方向是end -> src
	while (src < end)
	{
		ch = *src++; // 得到获得的ASCII值,src指向下一个字符
		if (ch >= '0' && ch <= '9')
		{
			// 八位组迭代,比如192.168.8.217
			// 以192为例:
			// 0 -> 0 * 10 + 1 = 1 -> 1 * 10 + 9 = 19 -> 19 * 10 + 2 = 192
			// 在将192赋值到tmp的第一个字节上(第一个八位组)
			unsigned int new = *tp * 10 + (ch - '0');

			// 八位组中不能以0开头,比如192.168.08.217是错误的
			if (saw_digit && *tp == 0)
				return 0;
			// 某一个八位组值不能超过255
			if (new > 255)
				return 0;

			// 八位组赋值
			*tp = new;

			// 一般是在遇到'.'的时候,(! saw_digit)为0
			// 而在'.'之后的第一个数字置为1
			// 统计八位组的数目,由于在运行中,所以值不得超过4
			if (!saw_digit)
			{
				if (++octets > 4)
					return 0;
				saw_digit = 1;
			}
		}
		else if (ch == '.' && saw_digit)
		{
			if (octets == 4)
				return 0;

			// 下一个八位组赋值,必须为0,方面迭代
			// saw_digit标记为未遇到数值
			*++tp = 0;
			saw_digit = 0;
		}
		else
			return 0; // 其他字符,直接返回错误
	}
	if (octets < 4)
		return 0;
	memcpy(dst, tmp, NS_INADDRSZ);
	return 1;
}

static int hex_digit_value(char ch)
{
	if ('0' <= ch && ch <= '9')
		return ch - '0';
	if ('a' <= ch && ch <= 'f')
		return ch - 'a' + 10;
	if ('A' <= ch && ch <= 'F')
		return ch - 'A' + 10;
	return -1;
}

static int inet_pton6(const char *src, const char *src_endp, unsigned char *dst)
{
	unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
	const char *curtok;
	int ch;
	size_t xdigits_seen;    /* Number of hex digits since colon.  */
	unsigned int val;

	tp = memset(tmp, '\0', NS_IN6ADDRSZ);
	endp = tp + NS_IN6ADDRSZ;
	colonp = NULL;

	/* Leading :: requires some special handling.  */
	if (src == src_endp)
		return 0;
	if (*src == ':')
	{
		++src;
		if (src == src_endp || *src != ':')
			return 0;
	}

	curtok = src;
	xdigits_seen = 0;
	val = 0;
	while (src < src_endp)
	{
		ch = *src++;
		int digit = hex_digit_value(ch);
		if (digit >= 0)
		{
			if (xdigits_seen == 4)
				return 0;
			val <<= 4;
			val |= digit;
			if (val > 0xffff)
				return 0;
			++xdigits_seen;
			continue;
		}
		if (ch == ':')
		{
			curtok = src;
			if (xdigits_seen == 0)
			{
				if (colonp)
					return 0;
				colonp = tp;
				continue;
			}
			else if (src == src_endp)
				return 0;
			if (tp + NS_INT16SZ > endp)
				return 0;
			*tp++ = (unsigned char)(val >> 8) & 0xff;
			*tp++ = (unsigned char)val & 0xff;
			xdigits_seen = 0;
			val = 0;
			continue;
		}
		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
			&& inet_pton4(curtok, src_endp, tp) > 0)
		{
			tp += NS_INADDRSZ;
			xdigits_seen = 0;
			break;  /* '\0' was seen by inet_pton4.  */
		}
		return 0;
	}
	if (xdigits_seen > 0)
	{
		if (tp + NS_INT16SZ > endp)
			return 0;
		*tp++ = (unsigned char)(val >> 8) & 0xff;
		*tp++ = (unsigned char)val & 0xff;
	}
	if (colonp != NULL)
	{
		/* Replace :: with zeros.  */
		if (tp == endp)
			/* :: would expand to a zero-width field.  */
			return 0;
		size_t n = tp - colonp;
		memmove(endp - n, colonp, n);
		memset(colonp, 0, endp - n - colonp);
		tp = endp;
	}
	if (tp != endp)
		return 0;
	memcpy(dst, tmp, NS_IN6ADDRSZ);
	return 1;
}

int __inet_pton_length(int af, const char *src, size_t srclen, void *dst)
{
	switch (af)
	{
	case AF_INET:
		return inet_pton4(src, src + srclen, dst);
	case AF_INET6:
		return inet_pton6(src, src + srclen, dst);
	default:
		//__set_errno(EAFNOSUPPORT);
		return -1;
	}
}

//inet_pton
int __inet_pton(int af, const char *src, void *dst)
{
	return __inet_pton_length(af, src, strlen(src), dst);
}

inet_ntop:


#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size)
{
	static const char fmt[] = "%u.%u.%u.%u";
	char tmp[sizeof "255.255.255.255"];

	if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
		//__set_errno(ENOSPC);
		return (NULL);
	}
	return strcpy(dst, tmp);
}

/* const char *
* inet_ntop6(src, dst, size)
*	convert IPv6 binary address into presentation (printable) format
* author:
*	Paul Vixie, 1996.
*/
static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size)
{
	/*
	* Note that int32_t and int16_t need only be "at least" large enough
	* to contain a value of the specified size.  On some systems, like
	* Crays, there is no such thing as an integer variable with 16 bits.
	* Keep this in mind if you think this function should have been coded
	* to use pointer overlays.  All the world's not a VAX.
	*/
	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
	struct { int base, len; } best, cur;
	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
	int i;

	/*
	* Preprocess:
	*	Copy the input (bytewise) array into a wordwise array.
	*	Find the longest run of 0x00's in src[] for :: shorthanding.
	*/
	memset(words, '\0', sizeof words);
	for (i = 0; i < NS_IN6ADDRSZ; i += 2)
		words[i / 2] = (src[i] << 8) | src[i + 1];
	best.base = -1;
	cur.base = -1;
	best.len = 0;
	cur.len = 0;
	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
		if (words[i] == 0) {
			if (cur.base == -1)
				cur.base = i, cur.len = 1;
			else
				cur.len++;
		}
		else {
			if (cur.base != -1) {
				if (best.base == -1 || cur.len > best.len)
					best = cur;
				cur.base = -1;
			}
		}
	}
	if (cur.base != -1) {
		if (best.base == -1 || cur.len > best.len)
			best = cur;
	}
	if (best.base != -1 && best.len < 2)
		best.base = -1;

	/*
	* Format the result.
	*/
	tp = tmp;
	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
		/* Are we inside the best run of 0x00's? */
		if (best.base != -1 && i >= best.base &&
			i < (best.base + best.len)) {
			if (i == best.base)
				*tp++ = ':';
			continue;
		}
		/* Are we following an initial run of 0x00s or any real hex? */
		if (i != 0)
			*tp++ = ':';
		/* Is this address an encapsulated IPv4? */
		if (i == 6 && best.base == 0 &&
			(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
			if (!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
				return (NULL);
			tp += strlen(tp);
			break;
		}
		tp += SPRINTF((tp, "%x", words[i]));
	}
	/* Was it a trailing run of 0x00's? */
	if (best.base != -1 && (best.base + best.len) ==
		(NS_IN6ADDRSZ / NS_INT16SZ))
		*tp++ = ':';
	*tp++ = '\0';

	/*
	* Check for overflow, copy, and we're done.
	*/
	if ((socklen_t)(tp - tmp) > size) {
		//__set_errno(ENOSPC);
		return (NULL);
	}
	return strcpy(dst, tmp);
}


//inet_ntop
const char *inet_ntop1(int af, const void *src, char *dst, socklen_t size)
{
	switch (af) {
	case AF_INET:
		return (inet_ntop4(src, dst, size));
	case AF_INET6:
		return (inet_ntop6(src, dst, size));
	default:
		//__set_errno(EAFNOSUPPORT);
		return (NULL);
	}
	/* NOTREACHED */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/15427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDF转OFD ~java实现

PDF转OFD ~java实现 上篇文章记录了一下我第一次对接“超阅云”实现了ofd转pdf功能&#xff0c;想了想&#xff0c;还是再写一篇pdf转ofd的实现&#xff0c;其实对接的API基本一样&#xff0c;如果你是第一次看&#xff0c;建议先看看上一篇文章-“ofd转pdf” ———————…

Web前端——用CSS的常用样式制作一个炫酷的按钮

文章目录笔记&#xff1a;CSS的常用样式炫酷按钮效果实现笔记&#xff1a;CSS的常用样式 边框以及弧度样式 border-width&#xff1a;边框的线条宽度。 border-style&#xff1a;边框的样式&#xff0c;例如 solid实现 dotted 点线 dashed 虚线… border-color&#xff1a;边框…

Docker -- 01实践:使用Docker 快速安装Jenkins

使用Docker 快速安装Jenkins1. Docker install2. Jenkins install3. User Guide1.1 Big Data -- Postgres3. User Guide1.1 Big Data -- PostgresJenkins Website: https://www.jenkins.io/. 1. Docker install Docker 安装和基础知识 Docker install: https://blog.csdn.net/w…

TS学习笔记 类型标签 联合类型 枚举类型 泛型 类型别名

个人理解总结&#xff1a; js天生没有编译和类型检查的束缚 灵活好上手 结合项目使用时也可以做到热更新提升开发体验。 (需要编译的JAVA以前开发DEBUG很麻烦但现在有了容器编排技术&#xff0c;也可以实现类似效果) TS是JS的超集&#xff0c;添加了类型标注&#xff0c;不能直…

vulnhub靶机corrosion1

靶机下载地址&#xff1a;Corrosion: 1 ~ VulnHub Kail IP&#xff1a;192.168.174.128 Corrosion ip&#xff1a;192.168.174.133 思路&#xff1a; 靶机端口扫描&#xff0c;ssh日志反弹shell&#xff0c;linpeas脚本扫描&#xff0c;备份文件发现密码&#xff0c;爆破zi…

医疗器械设计时需要注意的事项

伴随着医疗器械的增加&#xff0c;经市场评估的医疗器械产品也趋向多样化&#xff0c;医疗器械设计也非常重要&#xff0c;下面小编就带大家了解一下开展医疗器械设计时需要注意什么? 说到医疗器械&#xff0c;相信大家都很熟悉。医疗器械有很多种&#xff0c;包括一类医疗器械…

【C++位图】1. 快速查找某个数据是否在一个集合中 2. 排序(全部插入,遍历一遍) 3. 求两个集合的交集、并集等

目录 问题&#xff1a;给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中。 2.简单实现一个位图 3.如何利用位图求两个集合的交集、并集 问题&#xff1a;给40亿个不重复的无符号整数&#xff0c;没排过序…

Golang入门笔记(14)—— 错误处理

来一个除以0的异常&#xff0c;代码如下&#xff1a; package mainimport "fmt"func main() {fmt.Println("before")divNum()fmt.Println("after") }func divNum() {num1 : 10num2 : 0result : num1 / num2fmt.Println(result) } console 异常&…

GitHub 昙花一现:《Spring Boot 趣味实战》神作开源几分钟被下架

又来给大家分享好书了&#xff1a;刘水镜老师的 Spring Boot 趣味实战&#xff0c;网上依旧是没有开源版本&#xff01;文末送上 刘水镜是谁&#xff1f; 十余年持续技术文章输出&#xff0c;CSDN 博客专家。2020 年《 Spring Boot 趣味私房课》专栏上线&#xff0c;凭借风趣…

创新案例|巴黎欧莱雅如何以内容+货架双轮驱动全渠道兴趣电商增长飞轮

对巴黎欧莱雅而言&#xff0c;兴趣电商作为内容场景为核心的平台&#xff0c;但货架场景已成为驱动增长的飞轮。巴黎欧莱雅团队注意到&#xff0c;抖音用户不只是被动地接受信息流推送&#xff0c;而是越来越倾向于主动搜索。消费者行为的重大变革意味着消费者不再满足于货找人…

【MFC】初识MFC(8)

MFC简介 微软提供的一个类库&#xff08;Class Libraries&#xff09;&#xff0c;封装了Windows的API&#xff0c;并且包含一个应用程序框架。 1、MFC是对前面窗口编程所用到的API进行封装&#xff0c;在Windows C基础上引入了C面向对象的思想&#xff0c;简单而言就是把API…

【论文翻译】2.5PC:一个更快的非阻塞原子提交协议

2.5-PC: A Faster and Non-Blocking Atomic Commit Protocol 目录1 介绍2 相关工作3 原子承诺和 3PC 概述4 为什么 3PC 是非阻塞的&#xff1f;5 2.5 PC6 2.5 PC 的非正式证明7 确认信息8 2.5 PC 机器证明参考摘要&#xff1a;我们提出 2.5PC&#xff0c;一种非阻塞原子提交协…

DNS与网站访问流程

1&#xff1a;dns与网址url简介 DNS是域名系统(DomainNameSystem)的缩写&#xff0c;域名系统是一中庞大而复杂的系统&#xff0c;但我们这里讲解重心并不是这个系统&#xff0c;而是指本地电脑dns是什么 讲到dns&#xff0c;我们就不得不讲讲网址和域名&#xff0c;我们经常会…

linux杀死进程的五种方法(kill)

添加链接描述 相关博主的链接&#xff1b; 方法一&#xff1a;通过kill 进程id的方式可以实现 首先需要知道进程id, 例如,想要杀死firefox的进程,通过 ps -ef|grep firefox,可以查到firefox的进程id: 然后通过 kill 3781 就可以关闭进程了. 补充: kill -9 来强制终止退出, 例…

16.一篇文章学会django模型的使用

1.django模型简单示例 1.1 创建django项目 创建完项目&#xff0c;还需要创建django子项目 django-admin startproject model_study cd .\model_study\ python manage.py startapp model_app1.2配置应用 将模型对应的应用程序&#xff08;刚刚创建的子应用&#xff09;添加…

CentOS 7 Jenkins配置及SpringBoot项目自动部署

1.下载Jenkins 下载地址:War Jenkins Packages 运行Jenkins之前确保系统已经安装好JDK&#xff0c;因为我安装的是JDK1.8,所以选择2.346.1 这个版本 2.启动jenkins 将下载好的jenkins.war上传到服务器上,我的目录是/home/jenkins 启动命令 java -jar jenkins.war --httpPo…

万字详文:TCP 拥塞控制详解

本文主要介绍 TCP 拥塞控制算法&#xff0c;内容多来自网上各个大佬的博客及《TCP/IP 详解》一书&#xff0c;在此基础上进行梳理总结&#xff0c;与大家分享。因水平有限&#xff0c;内容多有不足之处&#xff0c; 敬请谅解。一、TCP 首部格式 在了解 TCP 的拥塞控制之前&…

多向思考者--高敏感人群的内心世界

工作以后很少看心理学的书&#xff0c;因为心理学书给我的印象是&#xff1a;国外翻译的很啰嗦&#xff0c;国内的太鸡汤&#xff0c;看的时候能有感触&#xff0c;看完以后就都忘记了。阅读心理学的书籍&#xff0c;更多的是跟着书中的内容和自己对话。看完《多向思考者》这本…

SpringMVC使用(二)

1. 统一异常处理 SpringMVC提供了统一处理Controller层抛出的异常的方法 1.1 统一异常处理案例 RestController的统一异常处理 package com.lan.controller;import com.lan.exception.BusinessException; import com.lan.exception.SystemException; import org.springfram…

DolphinDB Kafka 插件介绍

1. DolphinDB Kafka 插件介绍 DolphinDB Kafka 插件支持把 DolphinDB 中生产的数据推送到 Kafka&#xff0c;也支持从 Kafka 订阅数据&#xff0c;并在 DolphinDB 中消费。用户可以在 DolphinDB 中实例化 Producer 对象&#xff0c;把 DolphinDB 中的数据同步到 Kafka 中指定的…