开发虚拟串口驱动程序

虚拟串口设备驱动 字符设备驱动除了前面搭建好的框架外,接下来最重要的是实现设备的操作方法。 #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/kfifo.h> #define VSER_MAJOR 256 #define VSE 阅读详情

虚拟串口就是当本地并没有对应的串口硬件设备,而为应用层提供串口设备一样的系统调用接口,以兼容原本使用本地串口的应用软件的“虚”设备。本文作者给出了一种在Windows平台上实现虚拟串口的方法,由此实现的“串口”具有真实串口完全相同的系统调用接口。

在很多应用中需要用到虚拟串口,如在Modem卡出现之前,已经有了接在计算机串口上的外部Modem,而且各种拔号程序也是通过串口与外部Modem通信的。为了让已有的拔号程序不做修改,像使用外部Modem一样使用内置卡,就需要内置卡的驱动程序虚拟一个串口设备。又如当前工业界使用的一些串口服务器,往往有8个或16个甚至更多的串口,以连接多个串口设备,再通过一个网卡直接连入以太网。与它在同一网络上的计算机就通过以太网与串口服务器上挂接的串口设备通信。为了让计算机中原来使用本地串口的软件兼容,就需要在计算机上提供虚拟串口驱动。

虚拟串口的设计关键在于,该“串口”实现后必须具有与真实串口完全相同的系统调用接口。要做到这点,从已有的串口设备驱动程序上做修改是最佳捷径。下文就介绍以Windows NT上的串口驱动程序为基础,开发可运行于Windows NT、Windows 2000、Windows XP的各个版本虚拟串口驱动程序。

串口驱动中使用的几个链表

由于串口是双工设备,在一个读请求发出来还没有完成之前,同时可以发出写请求,加上在驱动程序层所有I/O请求都要求异步完成,即前一个请求尚没有完成,下一个相同的请求可能又来了。为此,串口驱动程序需要使用多个双向链表数据结构来处理各种IRP(I/O Request Packet,I/O请求包)。当收到一个IRP,先判断是否可立即完成,可以马上处理并返回,如果不允许则将IRP插在相应链表尾,在适当的时候如设备有空闲时处理,这时往往会产生一个硬件中断,激发DPC(Deferred Procedure Call,暂缓过程调用)过程,由DPC处理函数逐个从链表头取出IRP并试着完成它。串口驱动中有以下几个链表和DPC(在serial.h中有定义):

ReadQueue 和 CompleteReadDpc

用于保存Read IRP的链表和用于调度的DPC,与DPC对应的处理函数是SerialCompleteRead,它在read.c文件中,该函数的主要任务就是从ReadQueue中提取下一个IRP,并试着完成它。

WriteQueue 和 CompleteWriteDpc

用于保存Write IRP的链表和对应的DPC,与DPC对应的函数是SeriaCompleteWrite,它的实现在write.c中,该函数负责从WriteQueue中提取IRP,并试着完成它。

MaskQueue 和 CommWaitDpc

这一对链表用于处理Windows串口驱动的一个特性:事件驱动机制。它允许应用程序预设一个事件标志,而后等待与标志对应事件发生。DPC所调用的函数是SerialCompleteWait,它实现在Waitmask.c文件中,该函数也是试着从MaskQueue中提取IRP并完成它。

PurgeQueue

该链表与前面几个稍有不同,它没有与之相对应的DPC机制,而是在每次收到Purge请求时从PurgeQueue中逐个提取IRP并试着完成,因某种原因不能完成时则插入链表。相应的函数是purge.c文件中的SerialStartPurge。

以上机制是串口驱动程序的重要实现方法,在虚拟串口驱动中需要保留,但不同的是,硬件串口驱动中是ISR(中断服务程序)根据收、发或MODEM中断来激发相应的DPC,而在虚拟串口驱动中将因实际情况不同会有不同的激发机制。

DriverEntry的实现

DriverEntry是驱动程序的入口函数,相当于应用程序C语言中的main函数,开发一个虚拟串口驱动首先要修改的就是它。它的函数实体在initunlo.c文件中。只是在虚拟串口驱动中由于不与具体的硬件打交道,就不存在硬件资源分析、硬件初始化、判断其工作状态等处理,只需要为虚拟串建立设备对象、符号链接和初始化数据结构。一个典型函数实现大体如下:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

{

/*填写DriverObject->MajorFunction[]数组*/

/*建立设备对象*/

/*初始化SERIAL_DEVCIE_EXETENSION数据结构*/

Status = IoCreateDevice(DriverObject, sizeof(SERIAL_DEVICE_EXTENSION), &uniNameString, FILE_DEVICE_SERIAL_PORT, 0,TRUE,&deviceObject);

//初始化所有链表

InitializeListHead(&extension->ReadQueue);

InitializeListHead(…);

…;

//初始化所有DPC

KeInitializeDpc(&extension->CompleteReadDpc,SerailCompleteRead,extension);

KeInitializeDpc(…);

/*建立符号链接*/

SerialSetupExternalNaming(extension);

return Status;

}

SerialRead和SerialCompleteRead的实现

函数SerailRead和SerialCompleteRead决定了对Read IRP的响应策略,它们都存于read.c中。以串口服务器要用的虚拟串口为例,当串口服务器收到来自外部数据时将通过网络发至计算机,计算机则产生相应的网络中断并进行协议数据处理。网络接收线程缓存新收到的数据并激活CompleteReadDpc,从而SerialCompleteReadIrp得到调用,它再调用CompleteReadIrp对每个IRP进行处理。它们的实现大体如下:

NTSTATUS SerialRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)

{

/*此处略去变量声明和初始化*/

/*提取IRP中相关的数据*/

stack = IoGetCurrentIrpStackLocation(Irp);

ReadLen = stack->Parameters.Read.Length;

/*先看本地缓冲有数据否?有的话先读取*/

if(Extension->InCounter > 0 )

{ //注意这里要加锁,以防数据访问冲突

KeAcquireSpinLock(&Extension->

ReadBufferLock,&lIrql);

FirstRead = (ReadLen>Extension->

InCounter)? Extension->InCounter: ReadLen;

RtlCopyMemory(Irp->AssociatedIrp.

SystemBuffer,Extension->pInBuffer,FirstRead);

Extension->InCounter -= FirstRead;

ReadLen -= FirstRead;

KeReleaseSpinLock(&Extension->

ReadBufferLock,lIrql);//释放锁

}

/*是否已读到足够数据?是的话则完成该IRP*/

if( 0 == ReadLen)

{

status=STATUS_SUCCESS;

Irp->IoStatus.Status = status;

Irp->IoStatus.Information = FirstRead;

IoCompleteRequest(Irp,0);

return status;

}

/*没有则将IRP插入队列中,通过网络向串口服务器发出读数据请求*/

IoMarkIrpPending(Irp);

InsertWaitList(Extension->ReadQueue,Irp);

status = TdiSendAsync(Extension->ComChannel,pAckPacket,PacketLen(pAckPacket),(PVOID)ReadAckComplete,Irp);

/*返回PENDING,表示该IRP尚没有完成*/

return STATUS_PENDING;

}

Void CompleteReadIrp(IN PSERIAL_DEVICE_EXTENSION extension,IN PIRP Irp,IN PUCHAR pInData,IN ULONG Length )

{

/*此处略去变量声明和初始化*/

/*读取新数据*/

ReadLen = (ReadLen > Length)? Length : ReadLen;

if(ReadLen != 0)

{

RtlCopyMemory(pReadAsync->

pReadBuffer,pInData,ReadLen);

pReadAsync->pReadBuffer += ReadLen;

pReadAsync->ReadAlready += ReadLen;

extension->PerfStats.ReceivedCount +=

ReadLen;

}

else

{

/*因为串口服务器端只有在已经有了相应的数据或超过时间(此时,Length=0)才会发来应答并激活本DPC过程,所以此时已经超时,为了便于结束本IRP,这里有意改变TotalNeedRead,造成接收完毕的假象*/

pReadAsync->TotalNeedRead =

pReadAsync->ReadAlready;

}

if(pReadAsync->TotalNeedRead == pReadAsync->ReadAlready)

{

/*该IRP是否已经接收完毕,是的话则结束该

IRP*/

EndReadIrp(Irp);

/*从ReadQueue中取下一个IRP*/

}

/*本IRP没有完成也没有超时,则继续等待本DPC下次被激活,注意此时要判断IRP是否被要求取消*/

}

SerialWrite和SerailCompleteWrite的实现

SerialWrite和SerailCompleteWrite决定了Write IRP的实现。在SerialWrite中调用了网络发送函数TdiSendAsync,当该发送完成后将激活CompleteWriteDpc,调度SerialCompleteWrite函数,而它主要就是取出当前的WriteIRP,设置已经发送的数据数量,调用CompleteWriteIrp做该IRP的进一步处理。它们大体如下:

NTSTATUS SerialWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)

{

/*此处略去变量声明和初始化*/

/*从IRP中提取有关数据*/

stack=IoGetCurrentIrpStackLocation(Irp);

SendLen = stack->Parameters.Write.Length;

/*为网络发送和异步操作分配缓冲,在CompleteWrite中全部数据发送完后释放*/

pWriteAsync = ExAllocatePool(NonPagedPool,

SendLen+PACKET_HEADER_LEN+sizeof(WRITE_ASYNC));

if(pWriteAsync == NULL)

{

//错误处理

}

//保存异步数据

…

//设置网络发送数据包

BuildDataPacket(pPacket,WRITE,(USHORT)SendLen,pWriteAsync->pWriteBuffer);

/*先将IRP暂时阻塞并插入队列,在CompleteWrite中完成*/

IoMarkIrpPending(Irp);

InsertWaitList(extension->WriteQueue, Irp);

/*将写请求和相关数据通过网络发向串口服务器,由它负责将数据传到具体串口设备*/

status = TdiSendAsync(Extension->ComChannel,pPacket,PacketLen(pPacket),(PVOID)CompleteWriteIrp,Irp);

//统计数据累加

Extension->PerfStats.TransmittedCount += SendLen;

return STATUS_PENDING;

}

NTSTATUS CompleteWriteIrp(IN PDEVICE_OBJECT deviceobject,IN PIRP pIrp,IN PVOID context)

{

/*此处略去变量声明和初始化*/

SendLen=pWriteAsync->TotalNeedWrite - pWriteAsync->WroteAlready;

if(SendLen == 0)//全部数据发送完毕

{

EndWaitWriteIrp(pWriteIrp,STATUS_SUCCESS,

pWriteAsync->WroteAlready,pWriteAsync);

//从WriteQueue中取下一个IRP;

}

else //发送剩余数据

{

if(pWriteIrp->Cancel)

  {

//IRP被要求取消,完成WriteIrp

EndWaitWriteIrp(pWriteIrp,STATUS_CANCELLED,

pWriteAsync->WroteAlready,pWriteAsync);

return STATUS_CANCELED;

}

else

{

//再次设置网络数据包并发送

BuildDataPacket(…);

status = TdiSendAsync(…);

//统计数据累加

Extension->PerfStats.TransmittedCount +=

SendLen;

return STATUS_MORE_PROCESSING_REQUIRED;

}

}

}

其他几个接口函数的实现

除Read/Write外,SerialUnload、SerialCreateOpen、 SerialClose、SerialCleanup、SerailFlush等调用接口是硬件相关性比较弱的接口函数,基本不要修改,直接删除原来操作硬件的部分即可。复杂一点就是SerialIoControl,该接口函数包含有大量设置、读取串口硬件状态的处理,可建立一个本地数据结构随时保存虚拟串口的当前硬件状态。同时为了保证串口服务器端的真实串口状态和上层软件要求的一致,需要将所有设置请求通过网络发送到服务器端,由它负责改变真实硬件的状态。

(作者E-mail:mikeshujian@yahoo.com.cn)

最新虚拟串口 Virtual Serial Port Driver V11.0.1068 已经汉化 Virtual Serial Port Driver 11.0.1047 是一款功能强大的虚拟串口驱动程序,专为需要在开发和测试环境中模拟物理串口连接的用户设计。该版本于2023年4月5日发布,主要修复了在导入无效的COM端口捆绑设置时导致的崩溃问题,并优化了软件的自动更新功能。通过使用Virtual Serial Port Driver,用户可以在不依赖物理硬件的情况下,轻松创建和管理虚拟串口,极大地提高了开发和测试的效率。 阅读详情

相关推荐

STM32的USB虚拟串口驱动在Windows 7 64位和32位系统上无法正常安装的解决办法-STM虚拟串口驱动在Windows 7上的终极解决方案

在使用STM32微控制器进行USB通信时,使用虚拟串口驱动是一种常见的方式。如果在设备管理器中没有找到"STM32 Virtual COM Port"设备,或者设备状态显示为错误或未知设备,我们可以尝试手动安装STM32虚拟串口驱动。通过遵循上述步骤和使用示例代码,您应该能够解决在Windows 7 64位和32位系统上无法正常安装STM32虚拟串口驱动的问题。完成安装后,设备管理器中的"STM32 Virtual COM Port"设备应该正常工作,并且可以通过相应的串口号进行访问。

UbiSqlserver的博客 4371

串口工具VSPD的安装与使用

在当今时代,开发串口设备及相关程序的工程师需要在正式对外发布产品前进行调试。这对于现在的电脑来说是个大难题,因为现在的电脑上可能没有串口。在碰到这种情况时,您也许可以尝试串口模拟。借助串口助手进行内容的收发,验证程序的正确性和可靠性。本文仅仅简单介绍了Virtual Serial Port Driver安装与使用,希望有帮助。

qq_40296728的博客 8568

智峰虚拟串口驱动:实现与应用

本文还有配套的精品资源,点击获取 简介:智峰工作室的虚拟串口驱动是一种软件技术,它通过创建虚拟端口来模拟物理串口行为,特别适用于物理端口数量不足或需要额外串口的场景。该驱动提供了一个高效、灵活的解决方案,并通过一系列步骤进行安装和配置。使用智峰虚拟串口驱动,用户可以实现高度的灵活性、模拟真实串口行为、实现网络串口映射和远程通信,以及在软件开发中进行串口通信的模拟和测试。 ...

weixin_34511754的博客 1735

虚拟串口驱动程序 6.9:串口通信开发的利器

虚拟串口驱动程序 6.9:串口通信开发的利器 【下载地址】虚拟串口驱动程序6.9下载 虚拟串口驱动程序 6.9 下载 项目地址: https://gitcode.com/open-source-toolkit/63a311 ...

gitblog_09799的博客 434

windows虚拟串口驱动开发

windows虚拟串口驱动开发,windows下驱动程序设计。

虚拟串口的完整源代码

虚拟串口的完整源代码,可以直接编译运行,有这方面爱好的开发者可以拿来学习一下。

【亲测免费】 虚拟串口驱动程序 6.9

虚拟串口驱动程序 6.9 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库提供了一个名为“虚拟串口驱动程序 6.9”的资源文件。该驱动程序的主要功能是模拟创建虚拟串口,并且可以虚拟两个串口之间的硬件连接。通过使用该驱动程序,用户可以在没有实际硬件设备的情况下,进行串口通信的开发和测试。 功能特点 虚拟串口创建:模拟创建多个虚拟串口,方便开发者在不同场景下进行串口通信...

gitblog_09768的博客 1099

汇编语言(第4版)王爽 课程设计2 详细实现(一、虚拟模式DOS运行篇)

由于虚拟模式的限制,我们编写的许多逻辑暂时不能被检验,而因为《汇编语言》编写时间较早,其所依赖的运行环境如今只能够依靠虚拟机来搭建。比如实模式DOS,搭建步骤比较繁琐,因此我将其它的部分放在下一篇文章中进行讲解。事实上,我们实现的程序属于《汇编语言》课程设计2中任务程序部分,其中的完整任务还涉及到将该任务程序安装到软盘等操作,这些也都需要在实模式下才能运行,所以统一放到下一篇文章进行实现。

m0_73327328的博客 2823

虚拟串口驱动程序下载介绍

虚拟串口驱动程序下载介绍 【下载地址】虚拟串口驱动程序下载介绍 虚拟串口驱动程序(vspd)是一款实用的工具,旨在帮助用户轻松配置串口,简化串口通信流程。无论是开发者还是普通用户,都能通过该程序快速建立虚拟串口连接,提升工作效率。支持多种操作系统环境,使用前请仔细阅读说明以确保正确操作。下载并体验这款串口配置好帮手,开启...

gitblog_06761的博客 405

BUSCO评估基因组的完整性

因为数据库收集的时候找的就是在不同的物种间都是单拷贝的基因,所以说在评估的物种里面应该也是单拷贝的状态才对。基因组层面评估:先去基因组上预测这些基因,再去做评估,如果说给他是一个注释好的基因集,这个时候提供的是一个蛋白集合,它就直接是去进行同源搜索,再去评估,看BUSCO数据库里面的这些单拷贝基因有或者无;首先,tblastn也是同源搜索,同源搜索之后,去对转录本进行读码框预测,预测完的结果还是去进行hmmsearch的搜索(hmmsearch是做蛋白质结构域搜索的),最终拿到BUSCO评估结果。

qq_64400864的博客 2959

Keil5实战:如何高效导出变量数据并实现可视化分析

本文详细介绍了在Keil5开发环境中,如何利用调试脚本高效导出程序运行时变量数据的方法。通过编写脚本自动捕获数据并保存为文件,再结合Excel或Python进行可视化分析,为嵌入式调试与算法优化提供了数据支撑,显著提升开发效率。

silver的专栏 1104

探索无线疆界:虚拟串口驱动程序6.9——无缝链接的串口通信解决方案

探索无线疆界:虚拟串口驱动程序6.9——无缝链接的串口通信解决方案 去发现同类优质开源项目:https://gitcode.com/ 在数字时代的浪潮中,串口通信依然是工业控制、嵌入式开发等领域不可或缺的技术之一。今天,我们为大家带来一款革新性的工具——《虚拟串口驱动程序 6.9》。它不仅为开发者解锁了无硬件限制的串口通信新世界,更是简化了教育与测试流程,成为了技术探索者手中的利剑。 ???? 项目介绍...

gitblog_09732的博客 797

win10自动修复-无限循环【通用完美】超简单解决办法

2020.02.14今个我的笔记本电脑(Thinkpad Carbon 7 X1)(win10)早晨起来发现蓝屏,上面显示自动修复失败,重启后依然自动修复失败,不断手动重启,始终是修复失败。然后上网开始搜集资料找解决办法。 前边介绍关闭自动修复,如何找出错文件的方法;如果想看最终解决办法,直接看第三部分 上网就会发现这种现象很常见,同时是电脑自动安装系统更新,或者安装某些驱动出现。解决办法也大...

y15941300574的博客 19万+

【亲测免费】 解决STM32虚拟串口无法识别问题的终极指南

解决STM32虚拟串口无法识别问题的终极指南 【下载地址】解决STM32虚拟串口无法识别问题的资源包分享 本资源包旨在帮助那些在使用STM32开发过程中遇到虚拟串口无法被电脑识别问题的工程师和开发者们。当你在开发基于STM32的USB虚拟串口应用时,如果遇到电脑无法识别相关的虚拟串口设备,本指南将为你提供详细的解决步骤和...

gitblog_06548的博客 873

【WRF数据准备】气象驱动数据-ERA5再分析数据(Copernicus)

【WRF数据准备】气象驱动数据-ERA5再分析数据

WW、forever的博客 5526

Python DEAP 库深度解析:从基础架构到高级应用

DEAP 是一个基于 Python 的开源框架,专门用于实现和运行各种进化算法,旨在帮助用户轻松地构建和调整进化算法,用于解决各种优化和搜索问题。本节中,介绍了 DEAP 相较于其它进化计算框架的优势,以及 DEAP 中重要的工具 creator 和 Toolbox。

盼小辉丶的博客 5070

【免费下载】 虚拟串口驱动程序 6.9 下载

虚拟串口驱动程序 6.9 下载 【下载地址】虚拟串口驱动程序6.9下载 虚拟串口驱动程序 6.9 下载 项目地址: https://gitcode.com/open-source-toolkit/63a311 ...

gitblog_09723的博客 757

windows 配置 libxml2

路径:\libiconv-1.9.2-1-src.zip\src\libiconv\1.9.2\libiconv-1.9.2\include\。执行完后,在当前win32目录中会生成了一个bin.msvc目录,其中就有开发需要的libxml2.lib和libxml2.dll文件。将 libiconv.la 复制到 新建的 lib 目录,并将其改名为 iconv.lib。路径:libiconv-1.9.2-1-bin.zip\lib\。将如下的 iconv.h 复制到新建的 include 目录。

SHELLCODE_8BIT的博客 3884

STM32虚拟串口驱动程序V1.5.0:实现STM32与电脑的无缝通信

STM32虚拟串口驱动程序V1.5.0:实现STM32与电脑的无缝通信 【下载地址】STM32虚拟串口驱动程序V1.5.0 STM32虚拟串口驱动程序V1.5.0为开发者提供了便捷的串口通信解决方案,适用于多种Windows操作系统,包括Windows 98SE到Windows 7。该驱动程序支持x86和x64平台,安装...

gitblog_06767的博客 353

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

解决STM32虚拟串口无法识别问题的资源包

解决STM32虚拟串口无法识别问题的资源包 【下载地址】解决STM32虚拟串口无法识别问题的资源包分享 本资源包旨在帮助那些在使用STM32开发过程中遇到虚拟串口无法被电脑识别问题的工程师和开发者们。当你在开发基于STM32的USB虚拟串口应用时,如果遇到电脑无法识别相关的虚拟串口设备,本指南将为你提供详细的解决步骤和必...

gitblog_06549的博客 555

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【免费下载】 STM32 虚拟串口驱动程序 V1.5.0

STM32 虚拟串口驱动程序 V1.5.0 【下载地址】STM32虚拟串口驱动程序V1.5.0 本仓库提供STM32的Windows操作系统兼容的虚拟串口驱动程序包——STM32 Win7/8虚拟串口Virtual ComPort Driver(版本V1.5.0)。此驱动不仅支持Windows 7与Windows 8的3...

gitblog_09803的博客 965

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【亲测免费】 STM32虚拟串口驱动程序V1.5.0

STM32虚拟串口驱动程序V1.5.0 【下载地址】STM32虚拟串口驱动程序V1.5.0 STM32虚拟串口驱动程序V1.5.0为开发者提供了便捷的串口通信解决方案,适用于多种Windows操作系统,包括Windows 98SE到Windows 7。该驱动程序支持x86和x64平台,安装简单,只需下载、解压并运行安装程...

gitblog_06777的博客 1010

com0com 的项目扩展与二次开发

com0com 是一个开源项目,旨在提供一个虚拟串口驱动程序。该程序可以在没有物理串口的情况下模拟串口的行为,允许应用程序之间通过虚拟串口进行通信,类似于USB转串口设备。这对于需要串口通信但硬件有限的应用场景非常有用。 ## 2. 项目的核心功能 项目的核心功能是创建和管理虚拟串口。主要特点包括: - 支持多个虚拟串口的创建和管理。 - 允许应用程序通过虚拟串口进行数据传输。 - 提供了串...

gitblog_01016的博客 875

虚拟串口

最近学习了一些WDM驱动的知识,弄了下虚拟串口驱动。虚拟串口就是当计算机上没有相应的串口硬件,通过一个虚拟的串口驱动程序,在计算机上虚拟出若干个串口,这些虚拟出来的串口对于应用层来说就好象是真的有这些串口硬件一样。一般计算机上只有1到2个串口,也可以买几个USB转串口的设备,或者是PCI串口卡,通过这样的途径也只能增加几个串口,这并不能满足一些工业控制行业的需求,可能一台监控计算机上需要同时管理几...

weixin_30455023的博客 2937
上一篇: Windows图形驱动级远程屏幕传输的实现
下一篇: Delphi中Interface接口的使用方
Dcdu
博客等级 码龄21年 44粉丝 33原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值