Windows USB 编程
GUID
#include <initguid.h> // For DEFINE_GUID
// Device Interface GUID.
DEFINE_GUID(GUID_DEVINTERFACE_FOR_D3XX,
0xd1e8fe6a, 0xab75, 0x4d9e, 0x97, 0xd2, 0x6, 0xfa, 0x22, 0xc7, 0x73, 0x6c);
GUID DeviceGUID[2] = {0};
GUID是通过特定算法产生的一个二进制长度为128位的数字,在空间上和时间上具有唯一性,保证同一时间不同地方产生的数字不同。GUID的主要目的是产生完全唯一的数字。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。随机生成两个相同GUID的可能性是非常小的,但并不为0。
用了DEFINE_GUID,你可以使用在所有源文件中包含同一个头文件,在头文件中这样定义GUID:DEFINE_GUID(CLSID_MyObject,0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
在没有包含Initguid.h的地方,DEFINE_GUID宏创建外部引用来使用GUID值,在包含Initguid.h的地方,DEFINE_GUID重定义DEFINE_GUID宏以产生GUID的定义。
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8 ];
} GUID;
memcpy()
#include<string.h>
// Open a device handle by GUID
memcpy(&DeviceGUID[0], &GUID_DEVINTERFACE_FOR_D3XX, sizeof(GUID));
函数原型:void memcpy( voiddest, const void *src, size_t n );
函数功能:由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。
返回值: 函数返回一个指向dest的指针。
主要目的是,使用GUID唯一标识USB设备,并把打开USB设备的句柄存储到GUID的数据结构中。
memcmp()
#include<string.h>
//Compare bytes read with bytes written
memcmp(acWriteBuf, acReadBuf, sizeof(acReadBuf));
函数原型: int memcmp(const void *str1, const void *str2, size_t n)) ;
函数功能:把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
返回值: 如果返回值 < 0,则表示 str1 小于 str2。如果返回值 > 0,则表示 str2 小于 str1。如果返回值 = 0,则表示 str1 等于 str2。
isprint()
#include <ctype.h>
if (!isprint(pManufacturer[i]))
return FALSE;
函数原型:int isprint( int c );
函数功能:检查所传的字符是否是可打印的,可打印字符是非控制字符的字符。
返回值: 如果 c 是一个可打印的字符,则该函数返回非零值(true),否则返回 0(false)。
主要目的是,检验输入的参数是否正确。
OVERLAPPED
功能作用:Overlapped I/O的设计的目的:取代多线程功能(多线程存在同步机制,线程上下文切换是十分消耗CPU资源的)。Overlapped I/O模型是OS为你传递数据,完成上下文切换,在处理完之后通知你。由程序本身的处理,变为OS的处理(内部也是用线程处理的)。也就是说程序运行的同时,系统再开辟一个I/O操作的新线程,I/O操作的时间和线程执行其它任务的时间是重叠(OVERLAPPED)的。
// Create the overlapped io event for asynchronous transfer
OVERLAPPED vOverlappedWrite = {0};
vOverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Write asynchronously
// When FT_WritePipe is called with overlapped io,
// the function will immediately return with FT_IO_PENDING
ftStatus = FT_WritePipe(ftHandle, 0x02, acWriteBuf, ulBytesToWrite, &ulBytesWritten, &vOverlappedWrite);
if (ftStatus == FT_IO_PENDING)
{
// Poll until all data requested ulBytesToWrite is sent
do
{
// FT_GetOverlappedResult will return FT_IO_INCOMPLETE if not yet finish
ftStatus = FT_GetOverlappedResult(ftHandle, &vOverlappedWrite, &ulBytesWritten, FALSE);
if (ftStatus == FT_IO_INCOMPLETE)
{
continue;
}
else if (FT_FAILED(ftStatus))
{
CloseHandle(vOverlappedWrite.hEvent);
FT_Close(ftHandle);
return FALSE;
}
else //if (ftStatus == FT_OK)
{
// exit now
break;
}
}
while (1);
}
// Delete the overlapped io event
CloseHandle(vOverlappedWrite.hEvent);
程序解读:
因为 FT_WritePipe()是同步阻塞操作,如果要做到异步写操作,就要用到 vOverlapped parameter。
CreateEvent() 创建事件对象,指定该内核对象是自动重置的(FALSE)。并且指定该内核对象起始状态是未通知状态的(FALSE)。
当 FT_WritePipe() 用 overlapped IO 调用时,会立即返回 FT_IO_PENDING 。
进入循环的作用是判断写操作是否完成。通过 FT_GetOverlappedResult() 检测写操作是否完成,若未完成则返回 FT_IO_INCOMPLETE ;写操作线程继续,同时检测线程检测。
最后关闭事件对象。
你可以这样认为重叠IO,现在你已经进入一个服务器/客户机环境,请不要混淆概念,这里的服务器是指操作系统,而客户机是指你的程序(它进行IO操作),是当你进行IO操作(send,recv,writefile,readfile….)时你发送一个IO请求给服务器(操作系统),由服务器来完成你需要的操作,然后你什么事都没有了(有点像开辟新线程),当服务器完成IO请求时它会通知你,当然在这期间你可以做任何事,一个常用的技巧是在发送重叠IO请求后,程序在一个循环中一边调用PeekMessage,TranslateMessage和DispatchMessage更新界面,同时调用 GetOverlappedResult等待服务器完成IO操作,更高效一点的做法是使用IO完成例程来处理服务器(操作系统)返回的结果,但并不是每个支持重叠IO操作的函数都支持完成例程如TransmitFile函数.
OVERLAPPED 数据结构:
typedef struct _OVERLAPPED {
DWORD Internal; //通常被保留,当GetOverlappedResult()传回False并且GatLastError()并非传回ERROR_IO_PENDINO时,该状态置为系统定的状态。
DWORD InternalHigh; //通常被保留,当GetOverlappedResult()传回False时,为被传输数据的长度。
DWORD Offset; //指定文件的位置,从该位置传送数据,文件位置是相对文件开始处的字节偏移量。调用 ReadFile或WriteFile函数之前调用进程设置这个成员,读写命名管道及通信设备时调用进程忽略这个成员;
DWORD OffsetHigh; //指定开始传送数据的字节偏移量的高位字,读写命名管道及通信设备时调用进程忽略这个成员;
HANDLE hEvent; //标识事件,数据传送完成时把它设为信号状态,调用ReadFil,eWriteFile,ConnectNamedPipe TransactNamedPipe函数前,调用进程设置这个成员. 相关函数CreateEvent ResetEvent GetOverlappedResult WaitForSingleObject CWinThread GetLastError
} OVERLAPPED, *LPOVERLAPPED;
CreateEvent 数据结构:
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
第一个参数:是安全描述符,设为NULL表示使用默认的安全描述符,并且子进程无法继承返回的句柄。
第二个参数:指定了该内核对象是人工重置(传递TRUE)的还是自动重置(传递FALSE)的。
第三个参数:指定了该内核对象起始状态是已通知(传递TRUE)还是未通知状态(FALSE)。
第四个参数:为要创建的事件内核对象起一个名字,如果传递NULL,则创建一个“匿名”的事件内核对象。如果不传递NULL,且系统中已经存在该名字的事件内核对象,则不创建新的事件内核对象而是打开这个已经存在的,返回它的句柄。
该函数如果成功,返回事件内核对象的句柄,这样就可以操纵它了。如果失败,返回NULL。
事件内核对象(hEvent):
事件内核对象最通常的用途是:让一个线程执行初始化工作,然后触发另一个线程,让它执行剩余的工作,一开始的时候我们将事件初始化为未触发状态,然后当线程完成初始化工作的时候触发事件。
一个事件内核对象的触发表示一个操作已经完成。有两种类型的事件内核对象:手动重置事件和自动重置事件。
当一个手动重置对象被触发的时候,正在等待该事件的所有线程都将变成可调度状态。而当一个自动重置事件被触发时,只有一个正在等待该事件的线程会变成可调度状态。
对同一个文件handle,系统有多个异步操作时(一边读文件头,一边写文件尾, 有一个完成,就会有信号,不能区分是那种操作。),为每个进行中的overlapped调用GetOverlappedResult是不好的作法。
SetEvent设置事件为触发状态,ResetEvent设置事件为未触发状态。
句柄一定要关闭,通过CloseHandle。
C++ 中_In_ 和_out_
__ In__ 表明定义的变量或参数是作为输入,即需要给这个参数赋值,传递给某个函数去执行;
__ out__ 表明定义的变量或参数是作为输出,即需要给该参数一个地址,函数内部往这个地址写数据;
//////////////////////////////////////////////////////////////////
// Setting of chip configuration ( enables/disables streaming mode )
//////////////////////////////////////////////////////////////////
BOOL StartStreamPipe(
FT_HANDLE ftHandle,
// _In_ : it's macro definition, need assign a value to parameter
_In_ UCHAR a_ucPipeID,
_In_ ULONG a_ulStreamSize
)
{
return FT_SetStreamPipe(ftHandle,
FALSE,
FALSE,
a_ucPipeID,
a_ulStreamSize
) == FT_OK ? TRUE : FALSE;
}
https://www.cnblogs.com/leon19870907/archive/2011/09/23/2186291.html
https://www.jianshu.com/p/3afc1eb5bd32
https://www.jianshu.com/p/cf8e7df5ff09
https://www.jianshu.com/p/2a6e22194cd3
Windows USB 编程的更多相关文章
- storysnail的Windows串口编程笔记
storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...
- USB编程研究之二(常见设备类型的GUID)
在USB编程之前要事先了解一下GUID的概念. 应用其他网页中的定义: 全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装.在许多流行软件应用程序(例如 Web 浏览器和媒体 ...
- windows多线程编程星球(一)
以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- windows核心编程---第二章 字符和字符串处理
使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...
- 回忆读windows 核心编程
看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对 ...
- linux tcp/ip编程和windows tcp/ip编程差别以及windows socket编程详解
最近要涉及对接现有应用visual c++开发的tcp客户端,花时间了解了下windows下tcp开发和linux的差别,从开发的角度而言,最大的差别是头文件(早期为了推广尽可能兼容,后面越来越扩展, ...
随机推荐
- Qt5.3.1,的linux平台体验之旅
1. samba安装:http://blog.csdn.net/voice_shen/article/details/7692605 2. 安装run, sudo chmod 777 filenam ...
- mybaits foreach
<select id="selectQuickConsultDoctorList" resultMap="BaseResultMap" parameter ...
- 编写高质量代码改善C#程序的157个建议——建议116:避免用非对称算法加密文件
建议116:避免用非对称算法加密文件 MD5值或者说HASH值是一种不可逆的算法.如果需要从密文还原成明文,那么就需要对称和非对称这两类可逆算法了. 对称算法示意图: 在对称算法中,首先需要发送方和接 ...
- makeword()
MAKEWORD(学习之用,转载) MAKEWORD 宏 平台:SDK 这个宏创建一个被指定变量连接而成的WORD变量.返回一个WORD变量. (注:typedef unsigned short WO ...
- 实用的chrome插件
有人说Chrome是世界上最好的浏览器,当然也会有不赞同.但不论怎样,工具而已,何必限制,任何一个用好了都能迅速提高我们的效率,不过还是推荐Chrome. 自然问题就变成:“为什么要用Chrome ...
- 使用Amazon Simple Queue Service(SQS) 实现简单的消息服务
一 引言 亚马逊Amazon作为云计算的领跑者推出了很多云服务,最近因为项目的原因,需要用到SQS服务,因此简要地写下这篇随笔,一来方便以后查阅,二来方便共享一些简单的操作. SQS即可以理解为一个 ...
- git command cheat sheet
clone:克隆 --non-bare:(默认值)一般的克隆方式 --bare:只克隆.git目录 --mirror:只克隆.git目录,并且还保持与origin的关联,可以fetch commit: ...
- [java]基于UDP的Socket通信Demo
java课编程作业:在老师给的demo的基础上实现客户端发送数据到服务器端,服务器端接受客户端后进行数据广播. 整体功能类似于聊天室,代码部分不是太难,但是在本机测试的时候出现这样的问题: 服务端通过 ...
- 2.iptables 匹配条件(基础)
基本匹配条件 -s 用于匹配报文的源地址,可以同时指定多个源地址,每个IP地址用逗号分开,也可以指定网段 iptables -t filter -I INPUT -s 192.168.1.111,19 ...
- “全栈2019”Java第七十四章:内部类与静态内部类相互嵌套
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...