[.NET] 查询当前已安装所有 Win32 与 UWP 应用

为了获取当前设备用户已安装的所有应用程序,
一般来讲有两种方案. 一种是通过查询 “shell:AppsFolder” 目录下所有项,
一种是从开始菜单中获取所有快捷方式, 然后加上查询所有已安装的 UWP 应用, 最后得到总列表.

如需代码参考, 请看 github.com/SlimeNull/WindowsAppsQuery 以及 github.com/OrgEleCho/CurvaLauncher 中的 ‘Run Applictions’ 部分.

查询 Win32 应用

查询已安装 Win32 应用程序, 目前有两种常用方式.

  • 查询注册表中 “卸载” 的子键
  • 搜寻开始菜单目录

通过注册表查询

注册表中, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 中列举了当前计算机的所有可卸载应用程序
如果是仅安装在当前用户中的应用程序, 则存储在 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall 下.

根据微软官方文档 Win32/MSI/卸载注册表键 中介绍, 上述注册表键的子键中, 属性与 MSI 中的属性有以下对应关系:

Windows Installer 属性
DisplayNameProductName 属性
DisplayVersion派生自 ProductVersion 属性
PublisherManufacturer 属性
VersionMinor派生自 ProductVersion 属性
VersionMajor派生自 ProductVersion 属性
Version派生自 ProductVersion 属性
HelpLinkARPHELPLINK 属性
HelpTelephoneARPHELPTELEPHONE 属性
InstallDate此产品最后一次接受服务的时间。 每次从产品应用或移除修补程序或使用 /v 命令行选项修复产品时,都会替换此属性的值。 如果产品未接受任何修复或修补,则此属性包含在此计算机上安装该产品的时间。
InstallLocationARPINSTALLLOCATION 属性
InstallSourceSourceDir 属性
URLInfoAboutARPURLINFOABOUT 属性
URLUpdateInfoARPURLUPDATEINFO 属性
AuthorizedCDFPrefixARPAUTHORIZEDCDFPREFIX 属性
CommentsARPCOMMENTS 属性
提供给“添加或删除程序”控制面板的注释。
ContactARPCONTACT 属性
提供给“添加或删除程序”控制面板的联系人。
EstimatedSize由 Windows Installer 确定和设置。
LanguageProductLanguage 属性
ModifyPath由 Windows Installer 确定和设置。
ReadmeARPREADME 属性
提供给“添加或删除程序”控制面板的自述文件。
UninstallString由 Windows Installer 确定和设置。
SettingsIdentifierMSIARPSETTINGSIDENTIFIER 属性

通过开始菜单目录查询

如果是搜寻开始菜单目录, 则是以下路径:

当前用户的开始菜单程序列表: C:\Users\slime\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
所有用户公共的开始菜单程序列表: C:\ProgramData\Microsoft\Windows\Start Menu\Programs

通过 Environment.GetFolderPath 方法即可获取上述两个路径. 参数分别是 Programs 枚举和 CommonPrograms 枚举

所有正常安装的 Win32 程序一般都会创建开始菜单项, 所以可以通过这个粗略的获取所有 Win32 应用程序列表.

然后, 所有的应用程序都是通过快捷方式存在于开始菜单中的, 所以你需要有解析快捷方式的方案, 第一种是通过 Shell API, 但这挺麻烦的.
笔者这边推荐的方式是通过 Securify.ShellLink 这个库来解析.

// 从文件读取快捷方式信息
var shortcut = Shortcut.ReadFromFile(@"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Paint.lnk");

需要注意的是, 快捷方式的结构是很复杂的, 你想要的 “目标路径” 可能在快捷方式中不一定哪个属性中, 可以参考以下的 Fallback 顺序:

  • ExtraData.EnvironmentVariableDataBlock.TargetUnicode
  • LinkTargetIDList.Path
  • LinkTargetIDList.DisplayName

在获取这些属性时, 记得对属性进行判空, 以免遇到 NullReferenceException

如果要获取其他信息, 诸如命令行参数, 工作目录, 图标此类, 直接获取快捷方式的对应属性即可.
至于以管理员权限身份运行, 这个直接判断 LinkFlags 是否有 RunAsUser 这个标志就可以了.


查询 UWP 应用

查询已安装的 UWP 应用程序, 有你能轻易在网上找到的三种查询方式, 以及笔者自己找到的第四种方式.

  • 使用 Windows SDK 中的 PackageManager 类进行最正规的查询
  • 使用防火墙的 API, 通过查询 UWP 容器列表, 实现查找所有 UWP 应用
  • 调用 PowerShell, 执行 Get-AppxPackage
  • 查注册表

通过 Windows SDK 查询

第一种方案, PackageManager 并不是你可以直接使用到的类, 而是需要使用 Windows SDK 才可以用的. 对项目的配置方式也简单.

如果你是 .NET CoreCLR 的项目, 例如 .NET8 的, 那么直接右键项目, 打开属性, 将目标 OS 改为 Windows, 目标 OS 版本改为你的目标系统版本, 支持的 OS 版本则是最低 OS 版本.
这里建议 1904 什么的, 例如 10.0.19041.0, 选择更低的版本, 可以支持更多系统.

如果你是 .NET Framework 的项目, 那么你需要知道你的 Windows SDK 安装在哪, 在它下面会有一个 Windows.winmd 动态链接库, 它大概在一个叫 ‘UnionMetadata’ 的目录下, 右键你的项目, 添加引用, 然后把这个 winmd 库添加进去即可.

配置完之后, 你就可以使用 ‘PackageManager’ 进行查询了, 查询当前用户的所有已安装的包不需要什么特殊权限, 代码如下:

using System.Security.Principal;
using Windows.Management.Deployment;PackageManager packageManager = new PackageManager();
var packages = packageManager.FindPackagesForUser(WindowsIdentity.GetCurrent().User!.Value);

通过防火墙 API 查询

第二种方案, 通过 WinAPI NetworkIsolationEnumAppContainers 枚举所有的应用程序容器, 进而实现查询 UWP 应用程序.

非托管函数声明以及结构体定义

public static class NativeDll
{/// <summary>/// 加载资源文本/// </summary>/// <param name="pszSource">资源标识符</param>/// <param name="pszOutBuf">输出的缓冲区</param>/// <param name="cchOutBuf">缓冲区大小</param>/// <param name="ppvReserved">保留, 固定0</param>/// <returns></returns>[DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, ThrowOnUnmappableChar = true)]public static extern unsafe uint SHLoadIndirectString(string pszSource, ref char pszOutBuf, int cchOutBuf, IntPtr ppvReserved);[DllImport("FirewallAPI.dll")]public static extern uint NetworkIsolationEnumAppContainers(uint Flags, out uint pdwCntPublicACs, out IntPtr ppPublicACs);[DllImport("FirewallAPI.dll")]public static extern void NetworkIsolationFreeAppContainers(IntPtr pACs);public static string? GetIndirectString(string str){Span<char> buffer = stackalloc char[4096];if (SHLoadIndirectString(str, ref buffer[0], buffer.Length, 0) != 0){return null;}return new string(buffer.TrimEnd('\0'));}
}internal struct INET_FIREWALL_APP_CONTAINER
{internal IntPtr appContainerSid;internal IntPtr userSid;[MarshalAs(UnmanagedType.LPWStr)]internal string appContainerName;[MarshalAs(UnmanagedType.LPWStr)]internal string displayName;[MarshalAs(UnmanagedType.LPWStr)]internal string description;internal INET_FIREWALL_AC_CAPABILITIES capabilities;internal INET_FIREWALL_AC_BINARIES binaries;[MarshalAs(UnmanagedType.LPWStr)]internal string workingDirectory;[MarshalAs(UnmanagedType.LPWStr)]internal string packageFullName;
}internal struct INET_FIREWALL_AC_CAPABILITIES
{public uint count;public IntPtr capabilities;
}internal struct INET_FIREWALL_AC_BINARIES
{public uint count;public IntPtr binaries;
}

简单封装一下应用容器类:

using System.Runtime.InteropServices;internal record class AppContainer
{public string DisplayName { get; set; }public string Description { get; set; }public string PackageFullName { get; set; }public string[] Binaries { get; set; } = [];public string WorkingDirectory { get; set; }public AppContainer(INET_FIREWALL_APP_CONTAINER info){PackageFullName = info.packageFullName;WorkingDirectory = info.workingDirectory;uint HRESULT = 0;Span<char> buffer = stackalloc char[4096];HRESULT = NativeDll.SHLoadIndirectString(info.displayName, ref buffer[0], buffer.Length, 0);if (HRESULT == 0)DisplayName = new string(buffer.TrimEnd('\0'));elseDisplayName = info.displayName;buffer.Clear();if (NativeDll.SHLoadIndirectString(info.description, ref buffer[0], buffer.Length, 0) == 0)Description = new string(buffer.TrimEnd('\0'));elseDescription = info.description;buffer.Clear();INET_FIREWALL_AC_BINARIES inet_FIREWALL_AC_BINARIES = info.binaries;if (inet_FIREWALL_AC_BINARIES.count > 0 && inet_FIREWALL_AC_BINARIES.binaries != 0){Binaries = new string[inet_FIREWALL_AC_BINARIES.count];for (int i = 0; i < inet_FIREWALL_AC_BINARIES.count; i++){var str = Marshal.PtrToStringUni(Marshal.ReadIntPtr(inet_FIREWALL_AC_BINARIES.binaries + nint.Size * i));;if (str?.StartsWith(@"\\?\") == true){str = str[4..];}if (str != null){Binaries[i] = str;}}}}
}

调用:

var enumResult = NativeDll.NetworkIsolationEnumAppContainers(0, out var num, out var ptr);
if (enumResult != 0)throw new Win32Exception((int)enumResult, Marshal.GetLastPInvokeErrorMessage());List<AppContainer> appContainers = new((int)num);
for (int i = 0; i < num; i++)
{var info = Marshal.PtrToStructure<INET_FIREWALL_APP_CONTAINER>(ptr + Marshal.SizeOf<INET_FIREWALL_APP_CONTAINER>() * i);appContainers.Add(new AppContainer(info));
}NativeDll.NetworkIsolationFreeAppContainers(ptr);foreach (var appContainer in appContainers)Console.WriteLine(appContainer);

这种方式调用也有一点缺点, 你无法获取应用程序的图标.
以上代码来自于 Ilyfairy

通过注册表查询

第三种方案, 在注册表的 “HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages” 下, 你可以看到所有已安装包的部分信息

其中 “PackageId” 是该包的 ID, 而 “PackageRootFolder” 直接给出了包的根文件夹, 而这个文件夹中, 我们可以找到包的清单文件 “AppxManifest.xml”

清单中列出了所有该包内所有应用程序的信息, 包括应用名称, LOGO, 以及该应用是否对用户可见(展示在开始菜单中)

部分应用程序, 在 Manifest 中, 应用程序的显示名称是直接以文本形式存在的, 但是也有一些是通过资源路径的形式存在的. 我们需要加载这个文本资源, 来获取其实际文本.

这里再次用到了 “SHLoadIndirectString” 这个 API:

[DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, ThrowOnUnmappableChar = true)]
static extern unsafe uint SHLoadIndirectString(string pszSource, ref char pszOutBuf, int cchOutBuf, IntPtr ppvReserved);

通过一个键获取其对应所有应用程序的逻辑如下:

// 类型定义
public abstract record class AppInfo
{private string? _queryRoot;public string Name { get; set; } = string.Empty;public string QueryRoot { get => _queryRoot ?? Name; set => _queryRoot = value; }public string[]? AlterQueryRoots { get; set; }
}public record class UwpAppInfo : AppInfo
{public string PackageId { get; set; } = string.Empty;public string FamilyID { get; set; } = string.Empty;public string PackageRootFolder { get; set; } = string.Empty;public string AppxManifestPath => Path.Combine(PackageRootFolder, "AppxManifest.xml");public string ApplicationId { get; set; } = string.Empty;public UwpAppLogo[] AppLogos { get; set; } = Array.Empty<UwpAppLogo>();public required string OriginRegistryKeyName { get; set; } = string.Empty;public record struct UwpAppLogo(int Size, string Path);
}// 方法定义
private IEnumerable<UwpAppInfo> GetUwpApps(RegistryKey subKey)
{if (subKey.GetValue("PackageID") is not string packageId)yield break;string packageFamilyId = Regex.Replace(packageId, "_.*__", "_");if (subKey.GetValue("PackageRootFolder") is not string packageRootFolder)yield break;string packageManifestPath = Path.Combine(packageRootFolder, "AppxManifest.xml");if (!System.IO.File.Exists(packageManifestPath))yield break;var appxManifestContent = File.ReadAllText(packageManifestPath);XmlDocument xml = new();xml.LoadXml(appxManifestContent);XmlNamespaceManager nsManager = new XmlNamespaceManager(xml.NameTable);//这一步实例化一个xml命名空间管理器nsManager.AddNamespace("ns", "http://schemas.microsoft.com/appx/manifest/foundation/windows10");nsManager.AddNamespace("uap", "http://schemas.microsoft.com/appx/manifest/uap/windows10");var idNode = xml.SelectSingleNode("/ns:Package/ns:Identity", nsManager);var appNodes = xml.SelectNodes("/ns:Package/ns:Applications/ns:Application", nsManager);if (appNodes == null)yield break;foreach (XmlNode appNode in appNodes){var visualElementsNode = appNode.SelectSingleNode("uap:VisualElements", nsManager);if (visualElementsNode == null)continue;if (visualElementsNode?.Attributes?["AppListEntry"]?.Value is string appListEntry &&appListEntry.Equals("none", StringComparison.OrdinalIgnoreCase))continue;if (visualElementsNode?.Attributes?["DisplayName"]?.Value is not string displayName)continue;UwpAppInfo info = new(){OriginRegistryKeyName = Path.GetFileName(subKey.Name)};info.PackageId = packageId;info.FamilyID = packageFamilyId;info.PackageRootFolder = packageRootFolder;var logoNode = xml.SelectSingleNode("/ns:Package/ns:Properties/ns:Logo", nsManager);if (appNode == null ||appNode.Attributes?["Id"]?.Value is not string appId)continue;info.ApplicationId = appId;if (displayName.StartsWith(resourcePrefix)){string resourcePath = displayName.Substring(resourcePrefix.Length);// 非绝对路径, 且能够找到 Identity 节点if (!resourcePath.StartsWith("//") &&idNode?.Attributes?["Name"]?.Value is string id){// 不是引用其他资源, 则添加 'Resource' 前缀if (!resourcePath.Contains("Resources"))resourcePath = $"Resources/{resourcePath}";// 转为绝对资源resourcePath = $"//{id}/{resourcePath}";}string resourceStr = $"@{{{packageId}?ms-resource:{resourcePath}}}";uint errCode = SHLoadIndirectString(resourceStr, ref displayNameBuffer[0], displayNameBuffer.Length, 0);int endIndex = Array.IndexOf(displayNameBuffer, '\0');displayName = new string(displayNameBuffer, 0, endIndex);if (errCode != 0)continue;}if (string.IsNullOrWhiteSpace(displayName))continue;info.Name = displayName;string? logoPath = logoNode?.InnerText;if (logoPath is not null){var logoFullPath = Path.Combine(info.PackageRootFolder, logoPath);var logoFileName = Path.GetFileNameWithoutExtension(logoPath);var logoExtension = Path.GetExtension(logoPath);var logoFilesDir = Path.GetDirectoryName(logoFullPath) ?? ".";var logoFilesPattern = $"{logoFileName}*{logoExtension}";if (Directory.Exists(logoFilesDir)){var regex = new Regex($@"{Regex.Escape(logoFileName)}(\.scale-(?<scale>\d+))?{Regex.Escape(logoExtension)}");List<UwpAppInfo.UwpAppLogo> logos = new();foreach (var searchedLogoFile in Directory.EnumerateFiles(logoFilesDir, logoFilesPattern)){var searchedLogoFileName = Path.GetFileName(searchedLogoFile);var match = regex.Match(searchedLogoFileName);if (!match.Success)continue;int scale = 1;if (int.TryParse(match.Groups["scale"].Value, out var parsedScale))scale = parsedScale;logos.Add(new UwpAppInfo.UwpAppLogo(44 * scale, searchedLogoFile));}info.AppLogos = logos.ToArray();}}yield return info;}
}

上述代码来自于 github.com/OrgEleCho/CurvaLauncher 中 ‘Run Application’ 的 UWP 应用索引逻辑


查询 AppsFolder

使用 ‘运行’ 对话框, 打开 shell:AppsFolder, 你可以打开一个同时包含 Win32 和 UWP 应用的文件夹,
但这个文件夹实际上是不存在的, 它是 Shell 抽象出来的, 本质上是开始菜单的 CommonProgramsPrograms 目录, 以及所有 UWP 应用程序加起来, 构成的一个虚拟目录.

不过, 我们仍然可以通过编程手段来遍历这个 “目录”, 获取所有已安装的应用程序. 下面是通过 COM 查询 AppsFolder 的 C++ 代码.

#include <Windows.h>
#include <ShlObj.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
using namespace std;int main() {if (_setmode(_fileno(stdout), _O_U16TEXT) == -1) {wcout << L"Failed to set stdout to UTF-16" << endl;return -1;}HRESULT result;result = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);if (FAILED(result)) {wcout << L"CoInitializeEx failed: " << hex << result << endl;return -1;}IShellItem* appsFolder;result = SHGetKnownFolderItem(FOLDERID_AppsFolder, KF_FLAG_DEFAULT, nullptr, IID_PPV_ARGS(&appsFolder));if (FAILED(result)) {wcout << L"SHGetKnownFolderItem failed: " << hex << result << endl;return -1;}IEnumShellItems* appsFolderEnum;result = appsFolder->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&appsFolderEnum));if (FAILED(result)) {wcout << L"BindToHandler failed: " << hex << result << endl;return -1;}for (IShellItem* app; appsFolderEnum->Next(1, &app, nullptr) == S_OK; app->Release()) {// 获取应用程序的名称PWSTR name;result = app->GetDisplayName(SIGDN_NORMALDISPLAY, &name);if (FAILED(result)) {wcout << L"GetDisplayName failed: " << hex << result << endl;return -1;}wcout << name << L" -> ";CoTaskMemFree(name);// 获取应用程序的路径PWSTR path;result = app->GetDisplayName(SIGDN_PARENTRELATIVEPARSING, &path);if (FAILED(result)) {wcout << L"GetDisplayName failed: " << hex << result << endl;return -1;}wcout << path << L" = ";CoTaskMemFree(path);// 获取应用程序的图标IShellItemImageFactory* imageFactory;result = app->QueryInterface(IID_PPV_ARGS(&imageFactory));if (FAILED(result)) {wcout << L"QueryInterface failed: " << hex << result << endl;return -1;}HBITMAP bitmap;result = imageFactory->GetImage(SIZE { 64, 64 }, SIIGBF_ICONONLY, &bitmap);if (FAILED(result)) {wcout << L"GetImage failed: " << hex << result << endl;return -1;}wcout << bitmap << endl;DeleteObject(bitmap);imageFactory->Release();}appsFolderEnum->Release();appsFolder->Release();CoUninitialize();// 原神, 启动!// ShellExecuteW(nullptr, L"open", L"explorer", L"shell:AppsFolder\\Kingsoft.Office.ET", nullptr, SW_NORMAL);return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Web停车场管理系统

技术架构&#xff1a; Spring MVC JSP MySQL 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; 基于Web停车场管理系统主要用于实现停车场相关信息管理&#xff0c;基本功能包括&#xff1a;系统信息管理模块、车位信息管理模块、IC卡信息管理模块、固定车主…

【PaddleSpeech】语音合成-男声

环境安装 系统&#xff1a;Ubuntu > 16.04 源码下载 使用apt安装 build-essential sudo apt install build-essential 克隆 PaddleSpeech 仓库 # github下载 git clone https://github.com/PaddlePaddle/PaddleSpeech.git # 也可以从gitee下载 git clone https://gite…

后端软件三层架构

一、三层架构简介 三层架构是软件开发中广泛采用的一种经典架构模式&#xff0c;其核心价值在于通过清晰的任务划分来提高代码的可维护性和重用性。具体来说&#xff0c;三层架构主要包括以下三个层次&#xff1a; 持久层&#xff08;DAO层&#xff09;&#xff1a;这一层主要…

设备的层次结构 - 驱动程序的复杂层次结构

由于设备对象的水平结构和垂直结构&#xff0c;组成了Windows设备的树形结构图。在Windows中出事的时候会有一个根设备&#xff0c;为了理解简单&#xff0c;我们将PCI总线想象成根总线&#xff08;根总线其实不是PCI总线&#xff0c;只是为了理解方便&#xff09;。查到PCI总线…

京东物流基于 StarRocks 的数据分析平台建设

作者&#xff1a;京东物流 数据专家 刘敬斌 小编导读&#xff1a; 京东集团 2007 年开始自建物流&#xff0c;2017 年 4 月正式成立京东物流集团&#xff0c;截至目前&#xff0c;京东物流已经构建了一套全面的智能物流系统&#xff0c;实现服务自动化、运营数字化及决策智能化…

基于WordPress开发微信小程序1:搭建Wordpress

2年前&#xff0c;在知乎上提问&#xff1a;多数公司为什么宁愿自研也不用wordpress二次开发建站&#xff1f; - 知乎 (zhihu.com)&#xff0c;收到了&#xff0c;很多回答 自己打算做一下提升&#xff0c;便有了自己基于wordpress开发微信小程序的想法 项目定位 基于wordpre…

项目安全-----加密算法实现

目录 对称加密算法 AES &#xff08;ECB模式&#xff09; AES(CBC 模式)。 非对称加密 对称加密算法 对称加密算法&#xff0c;是使用相同的密钥进行加密和解密。使用对称加密算法来加密双方的通信的话&#xff0c;双方需要先约定一个密钥&#xff0c;加密方才能加密&#…

SpringBoot实战2

目录 1.如何返回两个类型的数据&#xff1f;User和Booth 2.如何使用MyBatis遍历一个数组进行查询&#xff1f; 3.前端要的数据太多太杂&#xff0c;我们拼接多个List&#xff0c;前端找数据困难&#xff0c;浪费时间。因此我们进行三表联表查询。 1.首先创建一个vo包&#x…

用Python和 Cryptography库给你的文件加密解密

用Python和 Cryptography库给你的文件加密解密 用Python和 Cryptography库给你的文件加把安全锁。 先介绍与加密解密有关的几个基本概念。 加密&#xff08;Encryption&#xff09;&#xff1a;加密是将明文转换为密文的过程&#xff0c;使得未经授权的人无法读懂。 解密&a…

带着问题读源码——Spring MVC是怎么找到接口实现类的?

引言 我们的产品主打金融服务领域&#xff0c;以B端客户为我们的核心合作伙伴&#xff0c;然而&#xff0c;我们的服务最终将惠及C端消费者。在技术实现上&#xff0c;我们采用了公司自主研发的微服务框架&#xff0c;该框架基于SpringBoot&#xff0c;旨在提供高效、可靠的服…

第八篇:node模版引擎Handlebars及他的高级用法(动态参数)

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; 引言&#xff1a; &#x1f…

Mac基于VMware安装CentOS

流程偏长&#xff0c;下一步根本点不完&#xff1b; 01 首先&#xff0c;明确下两款软件的版本信息&#xff1b; VMware是【VMware-Fusion-13.5.0】CentOS是【CentOS-7-x86_64-Minimal-1908】&#xff1b; VMware用来管理虚拟机系统&#xff0c;安装就不多说了&#xff0c;双…

match-case与if/elif/else(python)

if/elif/else语句应对一般场景&#xff0c;match-case主打复杂条件分支语句。 (笔记模板由python脚本于2024年01月28日 18:27:37创建&#xff0c;本篇笔记适合有一定编程基础&#xff0c;对python基础已比较扎实的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1…

npm ERR! reason: certificate has expired(淘宝镜像过期)

npm ERR! request to https://registry.npm.taobao.org/yauzl/-/yauzl-2.4.1.tgz failed, reason: certificate has expired 今天在执行npm install命令时&#xff0c;报错百度了下是淘宝证书过期原因 解决方法一 执行下面两个命令再进行npm install即可 npm cache clean --…

Kafka 记录

推荐资源 官网http://kafka.apache.org/Githubhttps://github.com/apache/kafka书籍《深入理解Kafka 核心设计与实践原理》 Kafka 架构 Kafka使用ZooKeeper作为其分布式协调框架&#xff0c;其动态扩容是通过ZooKeeper来实现的。Kafka使用Zookeeper保存broker的元数据和消费者信…

AI大语言模型学习笔记之三:协同深度学习的黑魔法 - GPU与Transformer模型

Transformer模型的崛起标志着人类在自然语言处理&#xff08;NLP&#xff09;和其他序列建模任务中取得了显著的突破性进展&#xff0c;而这一成就离不开GPU&#xff08;图形处理单元&#xff09;在深度学习中的高效率协同计算和处理。 Transformer模型是由Vaswani等人在2017年…

vio参数文件内相机imu参数的修改

imu标定工具 https://github.com/mintar/imu_utils网络上有各种IMU校准工具和校准教程&#xff0c;曾经花费了巨大精力跟着各种教程去跑校准。 然而&#xff0c;标定使用的数据都是在静止状态下录制的&#xff0c;我们在使用vio或者imu-cam联合标定的时候&#xff0c;imu确是处…

EF Core入门例子(以SqLite为数据库)

测试环境&#xff1a; visual studio 2017 .net core 2.1 具体步骤如下&#xff1a; 1 新增名称为EFCoreDemo的.net core控制台程序&#xff0c;版本选择.net core 2.1&#xff0c;项目不能放到带中文的目录下&#xff0c;不然到后面执行Add-Migration命令时会报如下的错误…

【数据结构】(二)线性表List

目录 1、基本概念 2、栈&#xff08;Stack&#xff09; 3、队列&#xff08;Queue&#xff09; 4、串&#xff08;String&#xff09; 1、基本概念 &#xff08;1&#xff09;线性表是零或多个数据元素的有限序列。 &#xff08;2&#xff09;数组长度指存储空间长度&…

android 网络拦截器统一处理请求参数和返回值加解密实现

前言 项目中遇到参数加密和返回结果加密的业务 这里写一下实现 一来加深记忆 二来为以后参考铺垫 需求 项目在开发中涉及到 登陆 发验证码 认证 等前期准备接口 这些接口需要单独处理 比如不加密 或者有其他的业务需求 剩下的是登陆成功以后的业务需求接口 针对入参和返回值…