GUID

在Windows环境下,驱动程序安装后如何通过GUID找到并连接设备,以及应用程序如何通过已连接的设备进行通信。

驱动程序安装成功后,应用程序的设计

VC6+DDK xp+DS3.2

 

 

驱动程序安装好后,应用程序要通过安装的驱动程序与设备的通信,但是应用程序怎么才能找到对应用的驱动程序呢?通过设备的GUID找到设备路径。

在windows操作系统环境下,设备通常被当作特殊文件处理。要打开设备,就要知道该设备的路径,要找到设备的路径,要使用GUID来查找。

 

设备在安装时,windows安装器和相应设备的驱动程序负责将相应的设备与对应的GUID联系起来,并将GUID写入注册表,这样通过GUID(接口类GUID)就可以找到对应设备。

 

对于HID设备,因为它的驱动已经集成在操作系统中,在同一系统中GUID是一样的,但通常这个值在不同的系统下也许会不一样所以一般不直接使用这个GUID,而是使用一个API函数来获取(函数是void _stdcall HidD_GetHidGuid(Out LPGUID HidGuid)).  而我们自己做的嵌入式设备,因为驱动是自己写的,所以GUID肯定不一样,而且这个GUID不会因为设备用在不同的操作系统上而改变,因为这个GUID在生成设备驱动的时候已经生成,就对应这个设备了,这个设备类GUID可以在每个驱动的interface.h文件中看到。我们就是要用这个文件中的GUID宏定义来查找已连接上设备,把系统中查到的设备列举出来,然后检查它的VID,PID以及设备版本号,看是不是要访问的设备,如果是,就可以对设备进行各种操作了,不是的话就循环下一个设备,直到找到或遍历完为止。

 

1.下面这个函数用来获取所有与ClassGuid指定的GUID相同的设备,当然对于HID设备在同一个pc机上可能会检测到多个,但是我们自己做的嵌入式设备,一般都是一个,要找到我们要的设备通过VID,PID以及设备版本号。该函数返回HDEVINFO句柄,这个句柄指向ClassGuid指定的所有设备的一个信息集合。这个句柄传给SetupDiEnumDeviceInterfaces()函数的第一个参数。

HDEVINFO SetupDiGetClassDevs(const GUID * ClassGuid,

                              PCTSTR     Enumerator                             

                              HWND      hwndParent

                              DWND      Flags

                              );

参数解析:

ClassGuid:设备的GUID指针。对于HID设备由函数void _stdcall HidD_GetHidGuid(Out LPGUID HidGuid)获得。对于自已做的嵌入式设备,因为驱动是我们自己写的,此设备类GUID在生成的驱动程序的interface.h中,是宏定义真接赋给此参数。

一个设备有两个GUID。一个是设备接口类GUID(Device Interface class GUID);一个是安装类GUID(Setup class GUID)。

 

设备接口类GUID在注册表HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/

DeviceClasses子键下。如果一个驱动程序安装好了,但是不知道它的接口类GUID,可以通过VID,PID等到DeviceClasses子键下中反查其GUID,注意,在DeviceClasses反查时有两个GUID目录下包含我们要找的VID,PID。其中有一个GUID目录包含好多设备路径,这个不是,另一个GUID目录仅包含一个设备的信息,这个才是我们要找到路径,在这个GUID目录下点#号,在右边可以看到一个名为SymbolicLink的项,它的值就是打开设备时要用到的路径(即设备接口名)。如果是通过DS生成的驱动,可以直接在interface.h中找到设备接口类的GUID,然后在注册表中找到它的位置。(不过既然在interface.h中找到了设备接口类GUID,就没必要再在注册表中找了,是吧?!)。

 

安装类GUID是设备安装时,由Windows安装器读取驱动程序inf文件中的安装类GUID添加到注册表中。HID设备的inf文件在Windows/inf文件夹下的input.inf.安装类GUID在注册表的HKEY_LOCAL_MACHINE_/SYSTEM/CurrentControlSet/Control/Class子键下,单击这个子键可以在右边找到在inf文件中设置的类名,图标等。再展开这个子键,可以看到0000子键和Properties子键。在0000子键下,可以看到用DS设置的子键(向导设置注册表时,Subkey表单项,Subkey表单项用来设置Value Name 表单项设置的注册表项出现的位置),单击这个子键,在右边就可以看到DeviceName(DeviceName就是Value Name表单项的值)项的键值(就是Default Value表单项填写的值),当然在inf文件中也能找到,因为它记录在inf文件中。单击0000子键,可以看到右边有很多表项,其中DriverDesc就是设备在设备管理器中显示的名称,InfPath是安装驱动后备份在Windows/inf目录(属性为隐藏)下的inf文件.MatchingDeviceId就是要匹配的硬件ID。(DS向导的注册表项的设置中,Type表单项用于设置这个新建的注册表项的类型,REG_SZ是字符串类型,根据Default Value的值而定。Root表单项设置需要增加到哪个根键下。Value Name表单项用于设置新建的注册表项名,Subkey表单项用于设置新建注册表项所在的根键,Default Value表单项就是新建表项的键值。Driver Variable Name是该项在驱动程序中出现的变量名)

同样在CurrentControlSet/Enum子键下,也有安装类GUID。

Enumerator:值为NULL表示将搜索全部设备;也可以指定一个设备的PnP名字的字符串,从而限制搜索。

hwndParent: 为父窗口的句柄,可以指定为NULL;

Flags:位4的值为1时,指定使用接口类GUID,位1为1时,表示列举出已经连接的设备,否则将连接全部安装的设备;

当函数调用失败时,将返回INVALID_HANDLE_VALUE,调用GetLastError()函数可以获取失败的原因。

 

BOOL SetupDiEnumDeviceInterfaces (HDEVINFO   DeviceInfoSet,

                               PSP_DEVINFO_DATA   DeviceInfoData,

                               Const GUID *InterfaceClassGuid,

                               DWORD     MemberIndex,

                               PSP_DEVICE_INTERFACE_DATA   DeviceInterfaceData

                               );

参数信息:

DeviceInfoSet(HDEVINFO类型):   SetupDiGetClassDevs函数返回的设备集合的句柄保存在这个参数中

DeviceInfoData(SP_DEVINFO_DATA类型的指针,SP_DEVINFO_DATA是结构体,PSP_DEVINFO_DATA此结构体的指针):强制获取某个设备的信息。通常为NULL  

InterfaceClassGuid:是指向设备的接口类GUID的指针,我们应用程序会指定一个变量来保存接口类GUID,假设为MyGUID(GUID类型),此时这个参数就会是&MyGuid。与第一个函数的参数值一样。

MemberIndex(设置为DWORD类型):用于控制现在SetupdinumDeviceInterfaces 函数获取的是哪一个设备的接口信息。0表示第一个设备,1为第二个设备。这个索引也是调用第一个函数时处理好的。索引的设备是第一个函数检测到的已连接的设备。当该值超过实际的索引数时,函数会返回零表示没找到与我们应用程序指定的VID,PID相符的设备;

DeviceInterfaceData(SP_DEVICE_INTERFACE_DATA类型指针):用来保存当前MemberIndex指定的设备的信息,在此函数调用前要先将该结构体变量的成员cbSize成员赋值为此结构体的大小。赋值的时候是&DeviceInterfaceData(定义:SP_DEVICE_INTERFACE_DATA   DeviceInterfaceData)

此函数的返回值为BOOL类型

 

BOOL SetupDiGetDeviceInterfaceDetail(HDEVINFO DeviceInfoSet,

                                   PSP_DEVICE_INTERFACE_DATA                                       DeviceInterfaceData,

                                   PSP_DEVICE_INTERFACE_DETALL_DATA   DeviceInterfaceDetailData,

                                   DWORD DeviceInterfaceDetailDataSize

                                   PDWORD RequiredSize

                                   PSP_DEVINFO_DATA   DeviceInfoData                   

                                   );

 

参数信息:

DeviceInfoSet:同样第一个函数的返回值;

DeviceInterfaceData:与第二个函数的最后一个参数一样

DeviceInterfaceDetailData: 比第二个参数获取的的设备信息还详细的设备信息,其中该结构体的成员变量DevicePath中就保存着用来打开设备的路径(或者叫设备接口名),该参数给API函数CreatFile以打开指定设备。在调用此函数之前,先要将该结构体的成员变量cbSize的值赋为该结构体的大小

DeviceInterfaceDetailDataSize:第三个参数所需的buffer大小。

RequiredSize:指定保存更详细设备信息所需要的buffer大小。

DeviceInfoData:是一个用来接收该接口所在设备的设备信息的结构体指针。通常值为NULL,表示该参数无效;

该函数调用两次,第一次获取保存设备详细信息buffer的大小,即RequiredSize,这时函数的第3,4个参数为NULL,等获取到buffer大小后,再次调用该函数此时第1,2,6都不变,第三个参数为buffer的地址,第四个为buffer大小。

记住当使用完后要销毁信息集合调用SetupDiDestroyDeviceInfoList(信息集合句柄);实现。

<think>我们正在讨论Vue中的guid(全局唯一标识符)相关内容。用户可能指的是在Vue应用中需要生成唯一ID的场景,例如为列表中的每个元素生成唯一键(key)或需要唯一标识某些组件实例。 在Vue中,我们通常使用唯一键(key)来帮助Vue高效地更新虚拟DOM。当使用v-for进行列表渲染时,为每个项分配一个唯一的key是推荐做法。但有时,数据本身可能没有唯一标识,我们需要生成一个全局唯一的ID(guid)作为key。 不过,需要注意的是,Vue本身并没有内置guid生成函数。我们可以使用第三方库或自己实现一个简单的唯一ID生成器。下面我们来详细讲解。 ### 1. 为什么需要guid? 在Vue中,为v-for提供key的目的是为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素。如果数据项的顺序可能会改变,我们不推荐使用索引作为key,因为当顺序改变时,索引也会变,这可能导致不必要的重新渲染或状态问题。此时,使用一个基于数据生成的唯一ID(guid)是更好的选择。 ### 2. 如何生成guid? 生成全局唯一标识符(GUID)或唯一ID(UUID)有多种方法。以下介绍几种常见方式: #### 方法1:使用第三方库 最常用的库是`uuid`,它支持生成符合RFC4122标准的UUID。 安装: ```bash npm install uuid ``` 在Vue组件中使用: ```javascript import { v4 as uuidv4 } from 'uuid'; export default { data() { return { items: [ { id: uuidv4(), name: 'Item 1' }, { id: uuidv4(), name: 'Item 2' }, ] } } } ``` 或者,在Vue 3的setup语法中: ```javascript import { ref } from 'vue'; import { v4 as uuidv4 } from 'uuid'; export default { setup() { const items = ref([ { id: uuidv4(), name: 'Item 1' }, { id: uuidv4(), name: 'Item 2' }, ]); return { items }; } } ``` #### 方法2:使用浏览器内置的`crypto` API 现代浏览器支持`crypto.randomUUID()`方法,它生成一个符合标准的UUID。注意:兼容性(IE不支持,但现代浏览器基本都支持)。 示例: ```javascript // 检查是否支持 if (typeof crypto === 'object' && typeof crypto.randomUUID === 'function') { const uuid = crypto.randomUUID(); console.log(uuid); // 例如: '36b8f84d-df4e-4d49-b662-bcde71a8764f' } ``` #### 方法3:自己实现简单的唯一ID生成器 如果你不需要严格的UUID格式,只需要一个足够唯一的字符串,可以自己实现一个简单的生成器。注意:自己实现的唯一性可能没有UUID强,但在某些场景下足够用。 示例: ```javascript function generateId() { return 'id-' + Date.now().toString(36) + '-' + Math.random().toString(36).substr(2, 9); } ``` 在组件中使用: ```javascript data() { return { items: [ { id: this.generateId(), text: 'Item A' }, { id: this.generateId(), text: 'Item B' } ] } }, methods: { generateId() { return 'id-' + Date.now().toString(36) + '-' + Math.random().toString(36).substr(2, 9); } } ``` ### 3. 在Vue中使用guid的注意事项 - **服务器渲染(SSR)**:如果使用SSR(如Nuxt.js),需确保ID生成在客户端和服务器端保持一致,否则可能导致hydration错误。通常,我们可以在mounted钩子中生成ID,或者使用一个在服务器端和客户端都能运行的UUID库(如`uuid`)。 - **性能**:在大型列表中,生成大量UUID可能会对性能产生影响(尽管uuid库已经优化)。在可能的情况下,尽量使用数据中已有的唯一标识。 - **响应性**:如果在data中生成ID,那么它是响应式的。但通常ID一旦生成就不会改变,所以也可以不用响应式,但Vue要求data中的属性都是响应式的。如果你不需要响应式,可以使用`Object.freeze`来避免不必要的开销。 ### 4. 替代方案:使用Vue的私有属性`_uid` 在Vue 2中,每个组件实例都有一个唯一的`_uid`属性。但是这个属性是Vue内部使用的,官方不建议在业务代码中使用,因为它可能在版本升级时改变。在Vue 3中,这个属性已被移除。 因此,不推荐使用`_uid`。 ### 5. 在Vue 3中使用唯一ID的另一种方式 在Vue 3中,我们可以使用`Symbol`来创建一个唯一的标识符,它可以在组件内使用。 示例: ```javascript import { defineComponent } from 'vue'; export default defineComponent({ setup() { const id = Symbol(); return { id }; } }); ``` 然后在模板中作为组件的key使用,但注意:Symbol不能直接作为字符串使用,所以如果我们需要字符串形式的ID,还是用UUID。 ### 小结 - 在Vue中生成guid,推荐使用`uuid`库或浏览器内置的`crypto.randomUUID()`。 - 避免使用Vue内部属性(如Vue2的`_uid`)。 - 在SSR场景下要注意客户端和服务端生成的ID一致性问题。 §§相关问题§§ 1. 在Vue中,为什么使用索引作为v-for的key是不推荐的? 2. 如何解决Vue SSR中客户端与服务端生成的ID不一致的问题? 3. 除了guid,还有哪些方式可以为Vue组件提供唯一标识? 4. 如何在Vue中高效地为大型列表生成唯一键? </think>### Vue 中 GUID 的使用与生成方法 在 Vue 中,**GUID(全局唯一标识符)** 主要用于需要唯一标识的场景,例如: 1. 动态渲染列表时作为 `v-for` 的 `key` 值 2. 组件实例的唯一标识 3. 状态管理中的唯一数据标识 4. 防止 XSS 攻击的安全令牌 --- #### 一、核心生成方法 Vue 本身不提供 GUID 生成工具,常用以下方式生成: ##### 1. 浏览器原生 API(推荐) ```javascript // 生成符合 RFC4122 标准的 UUID v4 const guid = crypto.randomUUID() // 示例: "d9a7d5b0-8e1a-4f7a-9f8c-6d3b2e1f4e9a" ``` - ✅ 优点: 原生支持、符合标准、无需依赖 - ⚠️ 兼容性: 需浏览器支持 [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) ##### 2. 第三方库 `uuid` ```bash npm install uuid ``` ```vue <script setup> import { v4 as uuidv4 } from 'uuid' const itemId = uuidv4() // 生成唯一ID </script> <template> <div v-for="item in list" :key="uuidv4()"> {{ item.name }} </div> </template> ``` ##### 3. 简化实现(非严格 GUID) ```javascript // 适用于简单场景 function simpleGuid() { return 'id-' + Date.now() + '-' + Math.random().toString(36).slice(2, 11) } ``` --- #### 二、Vue 中的关键应用场景 ##### 1. 列表渲染 (`v-for`) ```vue <template> <!-- 推荐使用唯一GUID而非数组索引 --> <ul> <li v-for="item in items" :key="item.id || generateGuid()"> {{ item.text }} </li> </ul> </template> <script> export default { methods: { generateGuid() { return crypto.randomUUID?.() || Date.now().toString(36) } } } </script> ``` ✅ **优点**: 避免数据变动时的渲染混乱[^1] ##### 2. 组件实例标识 ```vue <!-- CustomComponent.vue --> <script> export default { mounted() { this.instanceId = crypto.randomUUID() console.log(`组件ID: ${this.instanceId}`) } } </script> ``` ##### 3. Vuex/Pinia 状态管理 ```javascript // store.js import { defineStore } from 'pinia' export const useUserStore = defineStore('users', { actions: { addUser(user) { this.users.push({ ...user, id: crypto.randomUUID() }) } } }) ``` --- #### 三、关键注意事项 1. **SSR 兼容问题** 服务端渲染时需使用同构库(如 `uuid`),避免客户端/服务端 ID 不一致: ```javascript // nuxt.config.js export default { plugins: [{ src: '~/plugins/uuid.js', mode: 'server' }] } ``` 2. **性能优化** 大型列表中使用 GUID 作为 key 时,应提前生成而非动态计算: ```javascript data() { return { items: Array(1000).fill().map(() => ({ id: crypto.randomUUID(), data: /*...*/ })) } } ``` 3. **安全建议** - 敏感操作令牌需结合后端验证 - 避免在 URL 中暴露连续 GUID --- ### GUID 生成算法对比 | 方法 | 唯一性 | 标准符合 | 适用场景 | |------|--------|----------|----------| | `crypto.randomUUID()` | 极高 | RFC4122 v4 | 生产环境首选 | | `uuid` 库 | 极高 | RFC4122 | SSR/跨平台 | | `Date.now()` 简版 | 中等 | 非标准 | 开发测试 | | `Math.random()` | 低 | 非标准 | 临时数据 | --- ### 相关问题 1. 如何在 Vue SSR 中安全生成 GUID? 2. 使用 GUID 作为 `v-for` key 有哪些性能隐患? 3. Vue 3 的 `Teleport` 组件如何使用 GUID? 4. GUID 和自增 ID 在状态管理中的优劣对比? 5. 如何实现 Vue 组件的可复用实例标识? [^1]: Vue 官方文档建议使用唯一键值进行列表渲染,以保证高效的 DOM 更新策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值