当前位置: 首页 > news >正文

windows驱动开发-内核编程技术汇总(六)

在驱动程序中使用文件

内核模式组件通过其对象名称引用文件,该对象名称是连接到文件的完整路径的 \DosDevices 。 在 Microsoft Windows 2000 及更高版本的操作系统上, \?? 等效于 \DosDevices。例如,C:\WINDOWS\example.txt 文件的对象名称 \DosDevices\C:\WINDOWS\example.txt,我们可以使用对象名称打开文件的句柄。 

打开/读写文件

若要打开文件的句柄,请执行以下步骤:

  • 创建 OBJECT_ATTRIBUTES 结构,并调用 InitializeObjectAttributes 宏来初始化结构。 将文件的对象名称指定为 InitializeObjectAttributes 的 ObjectName 参数;
  • 通过将 OBJECT_ATTRIBUTES 结构传递给 IoCreateFile、 ZwCreateFile 或 ZwOpenFile,打开文件的句柄;
  • 如果文件不存在, IoCreateFile 和 ZwCreateFile 将创建该文件,而 ZwOpenFile 将返回STATUS_OBJECT_NAME_NOT_FOUND;

请注意,驱动程序几乎始终使用 ZwCreateFile 或 ZwOpenFile ,而不是 IoCreateFile。

调用 IoCreateFile、 ZwCreateFile 或 ZwOpenFile 时,Windows 主管会创建一个新的文件对象来表示文件,并为对象提供一个打开的句柄。 此文件对象将一直保留,直到你关闭所有打开的句柄。

无论调用哪个例程,都必须传递所需的访问权限作为 DesiredAccess 参数。 这些权限必须涵盖驱动程序将执行的所有操作。 请求的相应访问权限如下:

  • 从文件中读取:FILE_READ_DATA或GENERIC_READ
  • 向文件写入数据:FILE_WRITE_DATA或GENERIC_WRITE
  • 仅写入文件末尾:FILE_APPEND_DATA
  • 读取文件的元数据,例如文件的创建时间:FILE_READ_ATTRIBUTES或GENERIC_READ
  • 写入文件的元数据,例如文件的创建时间:FILE_WRITE_ATTRIBUTES或GENERIC_WRITE

下表列出了驱动程序可以对文件句柄执行的操作以及执行这些操作的相应例程。

  • 从文件读取数据:ZwReadFile
  • 将数据写入文件:ZwWriteFile
  • 读取文件或文件句柄的元数据:ZwQueryInformationFile
  • 写入文件或文件句柄的元数据:ZwSetInformationFile

若要指示开始读取或写入数据的文件中的位置,请分别将 ByteOffset 参数传递给 ZwReadFile 或 ZwWriteFile。

如果使用FILE_APPEND_DATA访问权限打开句柄,则所有数据将写入文件末尾,并忽略 ByteOffset 参数。

在某些情况下,I/O 管理器维护文件的当前文件位置指针。 可以通过为 ByteOffset 指定 NULL,在该位置开始读取或写入操作。 

若要检查或更改有关文件的信息,请分别调用 ZwQueryInformationFile 或 ZwSetInformationFile。 将特定类型的信息指定为每个例程的 FileInformationClass 参数。 例如,将 FileInformationClass 设置为 FileBasicInformation 可以检查或更改 FILE_BASIC_INFORMATION 结构,该结构包含文件创建时间和上次访问时间的成员等。

使用当前文件位置

创建或打开文件时,可能导致 I/O 管理器创建与文件句柄关联的当前文件位置指针。 执行此操作后,可以读取和写入当前文件位置的数据,I/O 管理器将按读取或写入的字节数自动更新位置。

默认情况下,I/O 管理器不维护当前文件位置指针。 此默认值可提供效率,因为正确维护当前文件位置需要 I/O 管理器同步文件对象上的每个读取和写入操作。

若要创建具有关联的当前文件位置指针的句柄,请在 DesiredAccess 参数中将 SYNCHRONIZE 访问权限指定为 ZwCreateFile、 IoCreateFile 或 ZwOpenFile,并在 CreateOptions 或 OpenOptions 参数中指定FILE_SYNCHRONOUS_IO_ALERT或FILE_SYNCHRONOUS_IO_NONALERT。 请确保不要同时指定FILE_APPEND_DATA访问权限。

ZwReadFile 和 ZwWriteFile 自动更新当前文件位置指针,使其指向受操作影响的数据之外。 例如,如果从字节偏移量 101 开始读取 20 个字节, 则 ZwReadFile 会将当前文件位置更新为 121。

可以通过分别调用 ZwQueryInformationFile 或 ZwSetInformationFile 来检查或更改当前文件位置。 在任一情况下,将 FileInformationClass 参数设置为 FilePositionInformation。

 注册表的使用

Windows 将注册表项表示为由对象管理器管理的执行对象。具体而言,每个键都有一个对象名称,你可以打开键的句柄。

用户模式应用程序访问与全局句柄相关的密钥,例如HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER。 但是,这些句柄不适用于内核模式代码。 相反,可以按键的对象名称来引用键。 所有注册表项的根目录都是 \Registry 对象。 全局句柄对应于 \Registry 对象的后代,如下所示:

  • HKEY_LOCAL_MACHINE:\Registry\Machine
  • HKEY_USERS:\Registry\User
  • HKEY_CLASSES_ROOT:没有等效的内核模式;
  • HKEY_CURRENT_USER:没有简单的内核模式等效项;

驱动程序可以通过执行以下步骤操作注册表项对象:

  • 打开注册表项对象的句柄;
  • 通过调用相应的 ZwXxx密钥 例程来执行预期操作。 有关如何执行此操作的信息,请参阅 使用 Registry-Key 对象的句柄;
  • 通过调用 ZwClose 关闭句柄;
打开/读写注册表

若要打开注册表项对象的句柄,请执行以下两个步骤:

  • 创建 OBJECT_ATTRIBUTES 结构,并通过调用 InitializeObjectAttributes 对其进行初始化。 指定要操作的键的名称作为 InitializeObjectAttributes 的 ObjectName 参数。如果将 NULL 作为 RootDirectory 参数传递给 InitializeObjectAttributes, 则 ObjectName 必须是注册表项的完整路径,从 \Registry 开始。 否则, RootDirectory 必须是键的打开句柄,而 ObjectName 是相对于该键的路径;
  • 通过调用 ZwCreateKey 或 ZwOpenKey 打开密钥对象的句柄,并将 OBJECT_ATTRIBUTES 结构传递给该对象。 如果该键尚不存在, ZwCreateKey 将创建密钥,而 ZwOpenKey 将返回STATUS_OBJECT_NAME_NOT_FOUND;

将 DesiredAccess 参数传递给包含所请求的访问权限的 ZwCreateKey 或 ZwOpenKey 。 必须指定允许驱动程序执行的操作的访问权限。 下面列出了可以执行的操作以及要请求的相应访问权限:

  • 获取注册表项值: KEY_QUERY_VALUE或KEY_READ
  • 设置注册表项值: KEY_SET_VALUE或KEY_WRITE
  • 循环访问键的所有子项:KEY_ENUMERATE_SUB_KEYS或KEY_READ
  • 创建子项: KEY_CREATE_SUB_KEY或KEY_WRITE
  • 删除密钥: DELETE

还可以调用 IoOpenDeviceRegistryKey 和 IoOpenDeviceInterfaceRegistryKey ,分别打开特定于设备的注册表项和设备接口特定的句柄。

注意 对于对 ZwCreateKey、 ZwOpenKey、 IoOpenDeviceRegistryKey 和 IoOpenDeviceInterfaceRegistryKey 的调用,泛型访问权限GENERIC_READ和GENERIC_WRITE在含义上等效于键特定的访问权限,分别KEY_READ和KEY_WRITE,并且可用作这些特定于密钥的访问权限的替代项。

下面列出了驱动程序可以对打开键执行的操作以及要调用的相应例程。

  • 检查密钥的属性,例如其名称或其子项的数目:ZwQueryKey
  • 循环访问密钥的子项,检查每个子项的属性:ZwEnumerateKey
  • 检查键值的属性,包括值的数据:ZwQueryValueKey
  • 循环访问键的值,检查每个键的属性:ZwEnumerateValueKey
  • 为与键关联的值设置数据:ZwSetValueKey
  • 删除密钥:ZwDeleteKey
  • 删除键值:ZwDeleteValueKey

驱动程序完成其操作后,必须调用 ZwClose 以关闭句柄,即使它已调用 ZwDeleteKey 来删除密钥。 (删除密钥后,其所有打开的句柄将变为无效,但驱动程序仍必须关闭 handle.)

下面的代码示例演示了如何为名为 \Registry\Machine\Software\MyCompanyMyApp 打开句柄,然后检索密钥数据并关闭句柄:

//
// Get the frame location from the registry key
// HKLM\SOFTWARE\MyCompany\MyApp.
// For example: "FrameLocation"="X:\\MyApp\\Frames"
// 
HANDLE              handleRegKey = NULL;
for (int n = 0; n < 1; n++) 
{NTSTATUS           status = NULL;UNICODE_STRING     RegistryKeyName;OBJECT_ATTRIBUTES  ObjectAttributes;RtlInitUnicodeString(&RegistryKeyName, L"\\Registry\\Machine\\Software\\MyCompany\\MyApp");InitializeObjectAttributes(&ObjectAttributes, &RegistryKeyName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,    // handleNULL);status = ZwOpenKey(&handleRegKey, KEY_READ, &ObjectAttributes);// If the driver cannot open the key, the driver cannot continue. // In this situation, the driver was probably set up incorrectly // and worst case, the driver cannot stream.if( NT_SUCCESS(status) == FALSE ) {break;}// The driver obtained the registry key.PKEY_VALUE_FULL_INFORMATION  pKeyInfo = NULL;UNICODE_STRING               ValueName;ULONG                        ulKeyInfoSize = 0;ULONG                        ulKeyInfoSizeNeeded = 0;// The driver requires the following value.RtlInitUnicodeString(&ValueName, L"FrameLocation");// Determine the required size of keyInfo.status = ZwQueryValueKey( handleRegKey,&ValueName,KeyValueFullInformation,pKeyInfo,ulKeyInfoSize,&ulKeyInfoSizeNeeded );// The driver expects one of the following errors.if( (status == STATUS_BUFFER_TOO_SMALL) || (status == STATUS_BUFFER_OVERFLOW) ){// Allocate the memory required for the key.ulKeyInfoSize = ulKeyInfoSizeNeeded;pKeyInfo = (PKEY_VALUE_FULL_INFORMATION) ExAllocatePoolWithTag( NonPagedPool, ulKeyInfoSizeNeeded, g_ulTag);if( NULL == pKeyInfo ){break;}RtlZeroMemory( pKeyInfo, ulKeyInfoSize );// Get the key data.status = ZwQueryValueKey( handleRegKey,&ValueName,KeyValueFullInformation,pKeyInfo,ulKeyInfoSize,&ulKeyInfoSizeNeeded );if( (status != STATUS_SUCCESS) || (ulKeyInfoSizeNeeded != ulKeyInfoSize) || (NULL == pKeyInfo) ){break;}// Fill in the frame location if it has not been filled in already.if ( NULL == m_szwFramePath ){m_ulFramePathLength = pKeyInfo->DataLength;ULONG_PTR   pSrc = NULL;pSrc = (ULONG_PTR) ( (PBYTE) pKeyInfo + pKeyInfo->DataOffset);m_szwFramePath = (LPWSTR) ExAllocatePoolWithTag( NonPagedPool, m_ulFramePathLength, g_ulTag);if ( NULL == m_szwFramePath ){m_ulFramePathLength = 0;break;}// Copy the frame path.RtlCopyMemory(m_szwFramePath, (PVOID) pSrc, m_ulFramePathLength);}// The driver is done with the pKeyInfo.xFreePoolWithTag(pKeyInfo, g_ulTag);} // if( (status == STATUS_BUFFER_TOO_SMALL) || (status == STATUS_BUFFER_OVERFLOW) )
} // Get the Frame location from the registry key.// All done with the registry.
if (NULL != handleRegKey)
{ZwClose(handleRegKey);
}

系统缓存内存中的密钥更改,并每隔几秒将其写入磁盘。 若要强制更改磁盘的密钥,请调用 ZwFlushKey。

若要通过更简单的接口操作注册表,驱动程序还可以调用 RtlXxx注册表Xxx 例程。 

注册表运行时库例程

若要操作注册表项,驱动程序可以调用 RtlXxxRegistryXxx 例程,该例程提供比 ZwXxxKey 例程更简单的接口。 执行此操作时,驱动程序不需要打开和关闭句柄;相反,驱动程序按名称引用密钥。

将 RelativeTo 和 Path 参数传递给每个 RtlXxx注册表Xxx 例程。 如果 RelativeTo 是RTL_REGISTRY_ABSOLUTE, 则 Path 指定项的完整路径,从 \Registry 根目录开始。 如果 RelativeTo 是RTL_REGISTRY_HANDLE, 则 Path 实际上是一个打开的句柄。Relative 的其他 RTL_REGISTRY_XXX 值 指定 键的公共根路径;在这些情况下, Path 指定相对于该根的路径。 例如,RTL_REGISTRY_USER要求 Path 相对于当前用户的注册表设置。 此值等效于在用户模式应用程序中指定HKEY_CURRENT_USER。)

下面列出了驱动程序可以通过调用 RtlXxx注册表Xxx 例程执行的操作:

  • 创建注册表项:RtlCreateRegistryKey
  • 检查是否存在注册表项:RtlCheckRegistryKey
  • 检查一个或多个注册表项值:RtlQueryRegistryValues
  • 编写注册表项值:RtlWriteRegistryValue
  • 删除注册表项值:RtlDeleteRegistryValue

下面的代码示例演示如何将 \Registry\Machine\System\KeyName 的 ValueName 设置为 ULONG 值0xFF:

NTSTATUS status;
ULONG data = 0xFF;status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,(PWCSTR)L"\\Registry\\Machine\\System\\KeyName",(PWCSTR)L"ValueName",REG_DWORD,&data,sizeof(ULONG));

尽管使用 RtlXxxRegistryXxx 例程(而不是 Zw Xxx Key 例程)时写入的代码行更少,但执行某些操作需要后一行代码。 例如,不存在与 ZwEnumerateKey 对应的 RtlXxxRegistryXxx 例程。

如果对同一键执行多个操作, 则 ZwXxx密钥 例程会更高效—你可以对每个操作使用相同的打开句柄。 相比之下, RtlXxx注册表Xxx 例程打开和关闭每个操作的新句柄。

相关文章:

windows驱动开发-内核编程技术汇总(六)

在驱动程序中使用文件 内核模式组件通过其对象名称引用文件&#xff0c;该对象名称是连接到文件的完整路径的 \DosDevices 。 在 Microsoft Windows 2000 及更高版本的操作系统上&#xff0c; \?? 等效于 \DosDevices。例如&#xff0c;C:\WINDOWS\example.txt 文件的对象名…...

Windows Server 2019虚拟机安装

目录 第一步、准备工作 第二步、部署虚拟机 第三步、 Windows Server 2019系统启动配置 第一步、准备工作 下载Windows Server 2019系统镜像 官网下载地址&#xff1a;Windows Server 2019 | Microsoft Evaluation Center VMware Workstation 17下载地址&#xff1a; 链…...

【软件工程】详细设计

目录 前言详细设计算法设计工具——判定表 前言 软件工程生命周期分为八个阶段&#xff1a; 问题定义—>可行性研究—>需求分析 —>概要设计—>详细设计—>编码与单元测试 —>综合测试—>软件维护 这节我们讲的是软件开发流程中的一个阶段&#xff0c;需求…...

在K8S中,集群可以做哪些优化?

在Kubernetes&#xff08;简称K8s&#xff09;集群中&#xff0c;可以进行多种优化以提升性能、稳定性和资源利用率。以下是一些常见的优化措施&#xff1a; 控制面组件优化&#xff1a; kube-apiserver 高可用与扩展&#xff1a;通过配置多个API服务器实例并使用负载均衡器分发…...

【C++】从零开始认识多态

送给大家一句话&#xff1a; 一个犹豫不决的灵魂&#xff0c;奋起抗击无穷的忧患&#xff0c;而内心又矛盾重重&#xff0c;真实生活就是如此。 ​​​​ – 詹姆斯・乔伊斯 《尤利西斯》 _φ(*&#xffe3;ω&#xffe3;)&#xff89;_φ(*&#xffe3;ω&#xffe3;)&…...

为什么叫“机器学习”Machine Learning 而不是“计算机学习”——深度学习Note

有一门学科“机器学习”火了起来&#xff0c;它是计算机科学与数学结合的产物&#xff0c;它的目的是使计算机“聪明”起来&#xff0c;实现人工智能。可是&#xff0c;令人困惑的是它明明就是计算机学习&#xff0c;为什么不叫“计算机学习”而叫“机器学习”呢&#xff1f;这…...

Spring Boot集成RabbitMQ-之6大模式总结

A.集成 一&#xff1a;添加依赖 在pom.xml文件中添加spring-boot-starter-amqp依赖&#xff0c;以便使用Spring Boot提供的RabbitMQ支持&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp&…...

后端开发面经系列 -- 滴滴C++一面面经

滴滴C一面面经 公众号&#xff1a;阿Q技术站 来源&#xff1a;https://www.nowcoder.com/feed/main/detail/38cf9704ef084e27903d2204352835ef 1、const在C和C区别&#xff0c;const定义的类成员变量如何初始化&#xff1f; 区别 C中的const&#xff1a; 在C中&#xff0c;c…...

Three.js的几何形状

在创建物体的时候&#xff0c;需要传入两个参数&#xff0c;一个是几何形状【Geometry】&#xff0c;一个是材质【Material】 几何形状主要是存储一个物体的顶点信息&#xff0c;在Three中可以通过指定一些特征来创建几何形状&#xff0c;比如使用半径来创建一个球体。 立方体…...

设计模式——单例模式(Singleton)

单例模式&#xff08;Singleton Pattern&#xff09;是设计模式中的一种&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问这个唯一实例。这种模式在多种场景下都非常有用&#xff0c;比如配置文件的读取、数据库连接的创建、线程池的管理等。 实现…...

springboot3项目练习详细步骤(第二部分:文章分类模块)

新增文章分类 接口文档 业务实现 参数校验 文章分类列表 接口文档 业务实现 获取文章分类详情 接口文档 业务实现 更新文章分类 接口文档 业务实现 分组校验 问题 概念 实现步骤 总结 删除文章分类 接口文档 业务实现 该模块大部分请求的路径相同&…...

VUE中父组件向子组件进行传值

在 Vue 中&#xff0c;父组件向子组件传值主要通过在子组件的标签上绑定属性&#xff08;props&#xff09;的方式来实现。以下是一个具体的示例。 父组件&#xff08;ParentComponent.vue&#xff09;: <template><div><!-- 父组件中使用子组件&#xff0c;并传…...

alpine安装中文字体

背景 最近在alpine容器中需要用到中文字体处理视频&#xff0c;不想从本地拷贝字体文件&#xff0c; 所以找到了一个中文的字体包font-droid-nonlatin&#xff0c;在此记录下。 安装 apk add font-droid-nonlatin安装好后会出现在目录下/usr/share/fonts/droid-nonlatin/ 这…...

JavaScript学习—JavaScript高级

原型链和继承 在 JavaScript 中&#xff0c;每个对象都有一个原型&#xff08;prototype&#xff09;&#xff0c;这个原型指向另一个对象。这个链式的原型关系被称为原型链。当访问一个对象的属性时&#xff0c;如果该对象没有该属性&#xff0c;它会沿着原型链向上查找&…...

CompletableFuture使用案例

优化代码时&#xff0c;除了Async注解&#xff0c;项目中如何使用多线程异步调用&#xff1f; 举个例子&#xff0c;去餐厅吃饭的时候。先点餐&#xff0c;厨师做菜&#xff0c;在厨师做菜的时候打游戏&#xff0c;然后根据厨师做的菜的口味去买矿泉水还是可乐。这样&#xff0…...

安卓使用so库

最近需要给小伙伴扫盲一下如何使用Android Studio 生成一个SO文件&#xff0c;网上找了很多都没有合适的样例&#xff0c;那只能自己来写一个了。 原先生成SO是一个很麻烦的事情&#xff0c;现在Android Studio帮忙做了很多的事情&#xff0c;基本只要管好自己的C代码即可。 …...

【介绍下LeetCode的使用方法】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…...

重学java 30.API 1.String字符串

于是&#xff0c;虚度的光阴换来了模糊 —— 24.5.8 一、String基础知识以及创建 1.String介绍 1.概述 String类代表字符串 2.特点 a.Java程序中的所有字符串字面值(如“abc”)都作为此类的实例(对象)实现 凡是带双引号的&#xff0c;都是String的对象 String s "abc&q…...

【区块链】共识算法简介

共识算法简介 区块链三要素&#xff1a; 去中心化共识算法智能合约 共识算法作为区块链三大核心技术之一&#xff0c;其重要性不言而喻。今天就来简单介绍共识算法的基本知识。 最简单的解释&#xff0c;共识算法就是要让所有节点达成共识&#xff0c;保证少数服从多数&#x…...

Qt---day2-信号与槽

1、思维导图 2、 拖拽式 源文件 #include "mywidget.h" #include "ui_mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::MyWidget) { ui->setupUi(this); //按钮2 this->btn2new QPushButton("按钮2",th…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...