博客 (14)

using System.Runtime.InteropServices;

/// <summary>
/// Windows 资源管理器的文件名排序规则(允许在非 Windows 平台使用)
/// <para>调用 Windows API(StrCmpLogicalW 函数)实现,仅在 Windows 平台环境中使用</para>
/// <para>基本规则如下:</para>
/// <para>将文件名中的数字作为数值来处理。</para>
/// <para>不区分大小写。</para>
/// <para>字符类型的大致优先级顺序为:特殊符号 → 数字 → 字母。</para>
/// <para>对于中文文件名,排序方式取决于系统的区域设置:拼音(默认)、笔画。</para>
/// </summary>
public class FileLogicalComparer : IComparer<string>
{
    [DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
    private static extern int StrCmpLogicalW(string psz1, string psz2);
    private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

    public int Compare(string? x, string? y)
    {
        // 处理 null 值情况
        if (x == null && y == null) return 0;
        if (x == null) return -1;
        if (y == null) return 1;

        try
        {
            if (IsWindows)
            {
                // Windows 平台:使用原生 API
                return StrCmpLogicalW(x, y);
            }
            else
            {
                // 非 Windows 平台:使用 C# 实现的回退方案
                return NaturalCompareFallback(x, y);
            }
        }
        catch (Exception) // 捕获 DllNotFound、EntryPointNotFoundException 等异常
        {
            // 异常时使用默认的字符串比较器
            return string.Compare(x, y, StringComparison.Ordinal);
        }
    }

    /// <summary>
    /// C# 实现的自然排序回退方案(代码来自 AI,未测试!)
    /// </summary>
    private static int NaturalCompareFallback(string x, string y)
    {
        if (x == y) return 0;

        int i = 0, j = 0;

        while (i < x.Length && j < y.Length)
        {
            if (char.IsDigit(x[i]) && char.IsDigit(y[j]))
            {
                // 提取连续数字并进行数值比较
                string num1 = ExtractNumber(x, ref i);
                string num2 = ExtractNumber(y, ref j);

                if (long.TryParse(num1, out long n1) && long.TryParse(num2, out long n2))
                {
                    if (n1 != n2)
                        return n1.CompareTo(n2);
                }
                else
                {
                    // 解析失败时按字符串比较
                    int strCompare = string.Compare(num1, num2, StringComparison.Ordinal);
                    if (strCompare != 0)
                        return strCompare;
                }
            }
            else
            {
                // 非数字字符直接比较
                if (x[i] != y[j])
                    return x[i].CompareTo(y[j]);

                i++;
                j++;
            }
        }

        return x.Length.CompareTo(y.Length);
    }

    /// <summary>
    /// 从字符串中提取连续的数字序列
    /// </summary>
    private static string ExtractNumber(string str, ref int index)
    {
        int start = index;
        while (index < str.Length && char.IsDigit(str[index]))
        {
            index++;
        }
        return str.Substring(start, index - start);
    }
}
xoyozo 1 年前
2,834

本文基于 manifest v3


插件使用 Web 技术开发

浏览器提供额外的插件 API

插件与网页分离,运行在一个独立的环境中


插件 API 功能

  • 管理 Tabs、窗口、历史记录、书签、Cookies、下载、浏览数据、通知、网站权限

  • 管理浏览器的外观和感觉 - 背景、主题、右键菜单、新标签页、启动页面

  • 定制 DevTools

  • 向网页注入脚本,与网页通信,与系统中的 Native 应用程序通信

  • 修改/监听发送的 HTTP 请求/接收的回复


插件构成

结构功能调用 API操作 Dom进程
manifest配置文件-

popup弹出对话框所有
Extension process
option page用户使用的设置页面所有

background script后台脚本所有禁止?Extension process
content script内容脚本(注入到网页中)有限允许Renderer process

* 即便 content script 是注入到网页中的,而且是运行在 Renderer 进程(与主网页相同的进程),但是它们仍运行在不同的世界(world)。主网页运行在 main world,插件的 content script 运行在 isolated world。比如说 main world 中有一个变量,它在 isolated world 中是访问不到的,但是如果修改了 dom,对其它世界是有影响的。


将 Chrome 插件迁移到 Edge

  • 移除 Chrome 独有的 API(如调用 Google 账户)

  • 移动 update_URL 字段(如果是从 Chrome 商店直接下载的包会有这个字段)

  • 改名 Chrome 相关的文字(插件名称、描述文字)


参考文献

  1. Microsoft Edge 扩展入门(官方)

  2. 一小时精通Edge扩展开发Microsoft Edge 文档(视频)

xoyozo 3 年前
2,613

image.png

“安装 VMware Tools”灰色无法点击。

image.png

打开虚拟机设置 - CD/DVD - 使用 ISO 映像文件,浏览到 VM 安装目录,根据对应操作系统选择镜像即可(如 linux.iso、windows.iso)

image.png

这样,虚拟机的计算机界面就会出现 VMware Tools 的安装包。

xoyozo 4 年前
7,328

测试在长度为 403 的字符串中查找,特意匹配最后几个字符:

string a = "";
for (int i = 0; i < 100; i++) { a += "aBcD"; }
a += "xYz";
string b = "xyz"; // 特意匹配最后几个字符

Stopwatch sw1 = Stopwatch.StartNew();
bool? r1 = null; 
for (int i = 0; i < 10000; i++) { r1 = a.IndexOf(b) >= 0; }
sw1.Stop();

Stopwatch sw2 = Stopwatch.StartNew();
bool? r2 = null; 
for (int i = 0; i < 10000; i++) { r2 = a.Contains(b); }
sw2.Stop();

Stopwatch sw3 = Stopwatch.StartNew();
bool? r3 = null; 
for (int i = 0; i < 10000; i++) { r3 = a.ToUpper().Contains(b.ToUpper()); }
sw3.Stop();

Stopwatch sw4 = Stopwatch.StartNew();
bool? r4 = null; 
for (int i = 0; i < 10000; i++) { r4 = a.ToLower().Contains(b.ToLower()); }
sw4.Stop();

Stopwatch sw5 = Stopwatch.StartNew();
bool? r5 = null; 
for (int i = 0; i < 10000; i++) { r5 = a.Contains(b, StringComparison.OrdinalIgnoreCase); }
sw5.Stop();

Stopwatch sw6 = Stopwatch.StartNew();
bool? r6 = null; 
for (int i = 0; i < 10000; i++) { r6 = a.Contains(b, StringComparison.CurrentCultureIgnoreCase); }
sw6.Stop();

Stopwatch sw7 = Stopwatch.StartNew();
bool? r7 = null; 
for (int i = 0; i < 10000; i++) { r7 = Regex.IsMatch(a, b); }
sw7.Stop();

Stopwatch sw8 = Stopwatch.StartNew();
bool? r8 = null; 
for (int i = 0; i < 10000; i++) { r8 = Regex.IsMatch(a, b, RegexOptions.IgnoreCase); }
sw8.Stop();

return Json(new
{
    IndexOf_________________ = sw1.Elapsed + " " + r1,
    Contains________________ = sw2.Elapsed + " " + r2,
    ToUpper_________________ = sw3.Elapsed + " " + r3,
    ToLower_________________ = sw4.Elapsed + " " + r4,
    OrdinalIgnoreCase_______ = sw5.Elapsed + " " + r5,
    CurrentCultureIgnoreCase = sw6.Elapsed + " " + r6,
    IsMatch_________________ = sw7.Elapsed + " " + r7,
    IsMatchIgnoreCase_______ = sw8.Elapsed + " " + r8,
});

结果参考:

{
"indexOf_________________": "00:00:00.1455812 False",
"contains________________": "00:00:00.0003791 False",
"toUpper_________________": "00:00:00.0038182 True",
"toLower_________________": "00:00:00.0026113 True",
"ordinalIgnoreCase_______": "00:00:00.0096550 True",
"currentCultureIgnoreCase": "00:00:00.1596517 True",
"isMatch_________________": "00:00:00.0053627 False",
"isMatchIgnoreCase_______": "00:00:00.0084132 True"
}


xoyozo 5 年前
2,310

命令格式:CertUtil -hashfile <文件名> <hash类型>

例:CertUtil -hashfile abc.iso SHA1

xoyozo 8 年前
6,624

本文记录 Newtonsoft.Json 的用法,System.Text.Json 请参此文。

如何在序列化时间类型时以“年-月-日 时:分:秒”的格式输出?

默认时间类型将序列化为:2017-11-10T18:48:14.1685763+08:00,我们只要 new 一个 IsoDateTimeConverter 即可改变时间类型的输出格式:

var dtc = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
string b = JsonConvert.SerializeObject(DateTime.Now, dtc);


如何将对象序列化为可友好阅读的字符串?

序列化后的字符串默认是“紧凑型”的,如:{"a":1,"b":2}

可以将 Formatting 指定为 Indented 即可输出格式化后的字符串,例:

var obj = new { a = 1, b = 2 };
string a = JsonConvert.SerializeObject(obj, Formatting.Indented);

结果如下:

{

  "a": 1,

  "b": 2

}


枚举类型输出为字符串,而非索引值

[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]

更多用法参:https://www.cnblogs.com/DomoYao/p/Json.html


不序列化属性

[Newtonsoft.Json.JsonIgnore]

当值为 null 时不序列化

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]


不序列化值为 null 的项

var jSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

JsonConvert.SerializeObject(obj, Formatting.Indented, jSetting);

xoyozo 9 年前
6,521

优点缺点
大白菜

可还原 U 盘空间

支持 UEFI

众多山寨产品,分不清哪个是正宗老牌,说不定还是新秀更优秀

Window 10 自带防病毒软件 Window Defender 提示发现威胁

一键制作的大白菜U盘,将 iso 拷入U盘后安装的纯净系统会被捆绑安装垃圾软件

老毛桃

可还原 U 盘空间

支持 UEFI

PE 还不错

“ISO 模式”没什么问题,但“一键制作”的是 FAT32 格式,不支持将大于 4GB 的 ISO 镜像拷贝到 U 盘

“模拟启动”可启动老毛桃界面,但直接写入硬盘映像的 U 盘无法模拟启动

卸载时,Window 10 自带防病毒软件 Window Defender 提示发现特洛伊木马

软碟通 UltraISO

中规中矩

写入硬盘不会自动还原 U 盘空间

网上找序列号激活

Ventoy

推荐!

开源

可同时拷入多个系统镜像文件,并支持启动时选择

可支持格式化为多种文件格式

一键制作,可升级

暂无

软碟通制作 Windows 系统安装盘过程:

  1. 下载微软官方提供的 iso 系统镜像文件

  2. 如果 U 盘容量缩水,或根本无法正常使用 U 盘,使用老毛桃还原 U 盘空间

  3. 打开 UltraISO,打开要写入 U 盘的 iso 文件

  4. 在菜单上选择:启动 - 写入硬盘映像...

  5. 选择硬盘驱动器,格式化,写入(注意:点击“写入”是按 FAT32 重新格式化的,若要制作 NTFS 文件系统的 U 盘,请先按 NTFS 格式化,然后在此界面上点击“便捷启动”-“便捷写入”)

  6. 如果 U 盘足够大,可以在 U 盘里多放几个系统镜像,双击打开另一个 iso,将所有文件和文件夹复制到 U 盘上新建的目录中。这样下次需要安装什么系统时,只要把对应的系统的文件放到 U 盘根目录,其它系统移到二级目录中即可。当然还可以往里面存放一些常用软件。

另外最好常备一个带有 PE 系统的启动盘,在旧电脑上安装旧系统时经常会用到。

如果在分区那步无法删除或创建分区(提示动态卷什么的),在确认放弃磁盘中的文件的前提下,可以使用 Shift + F10 调出命令行,键入 diskpart,列出磁盘(list disk),选择磁盘(select disk 0),清除(clean),注意 U 盘启动盘也会在列表中,勿删!

xoyozo 9 年前
24,827

在 VMware 虚拟机上安装 macOS 黑苹果系统的过程比较简单,分以下几个步骤进行:


1、用 Securable 工具检测电脑是否支持“虚拟技术”

2、下载并安装 VMware,写本文时最新版本 v12.5.5

3、下载 macOS 懒人版安装镜像,写本文时最新版本 v10.12.4

4、下载并安装 Unlocker,写本文时最新版本 v2.0.8,用于在 VM 中新建虚拟机时显示 Apple Mac OS X

5、新建虚拟机,用记事本打开虚拟机的配置文件 .vmx,底部加一行:smc.version = "0"

6、设置(详见下方链接图文教程) 

7、将镜像文件后缀名 .cdr 改为 .iso,加载到虚拟机的 CD/DVD 中,启动,运行磁盘工具进行分区

8、安装完成后推出 CD/DVD,安装 VMware Tools

9、如果觉得卡,进行一些操作


请参考:Hegel_SU 撰写的《VMware 12 安装 macOS S 10.12》详细图文教程

xoyozo 9 年前
5,827

本教程使用的软件版本:

VMware Workstation 12 Pro for Windows

Mac OS X Unlocker for VMware V2.0.6
一个能让虚拟机 VMware 安装 OS X 系统的解锁补丁

OS X 10.10.5 Yosemite (14F27) 懒人版 CDR 镜像
CRC32: C7E1E915
MD5: A76FF6E43058A40182435D274D9EB976
SHA-1: 7DDC194E779B003AFDCF2B7C11BEB6D4443F8D72

安装步骤:

1、安装 VMware Workstation

2、新建虚拟机:选择 典型 - 稍后安装操作系统,当然现在还看不到 Apple Mac OS X,先退出 VMware

3、安装 Unlocker

4、重复第 2 步,选择 Apple Mac OS X,并选择对应的 OS X 版本,后续跟据情况自行配置

5、编辑虚拟机设置 - CD/DVD(SATA) - 使用 ISO 镜像文件 - 浏览 - 所有文件(*.*),定位到 .cdr 镜像文件

6、开启此虚拟机

7、如果报错:VMware Workstation 不可恢复错误: (vcpu-0),打开新建虚拟机时指定的位置(默认在 C:\Users\用户名\Documents\Virtual Machines\虚拟机名\),用记事本打开 .vmx 文件,添加一条配置:smc.version = "0",保存关闭后重新开启虚拟机

8、如果屏幕中央出现一个禁止的图标,那么表示当前版本的 VMware 不支持安装当前版本的 OS X

9、如果在“选择要安装到的磁盘”界面仅列出了镜像文件而无法继续安装,请在窗口顶部的菜单栏中选择 实用工具 - 磁盘工具,选中新建虚拟机时创建的磁盘,切换到“分区”选项卡进行分区操作,简单地可以选择“1 个分区”,点击“应用”、“分区”,退出磁盘工具。现在可以把 OS X 安装在刚刚创建的分区上了

10、继续愉快地安装和使用 OS X 吧!

使用此方法将 OS X 安装到物理磁盘并支持开机直接运行,请参考此文:超详细 (60P)利用虚拟机安装10.9.4(懒人版)到真机教程

xoyozo 11 年前
5,549

版本区别

功能特性 Windows RT Windows 8
(标准版)
Windows8 Pro
(专业版)
Windows 8 Enterprise
(企业版)
与现有Windows 兼容 无 有 有 有
购买渠道 在设备上预装 大多数渠道 大多数渠道 经过认证的客户
架构 ARM (32-bit) IA-32 (32-bit) or x86-64 (64-bit) IA-32 (32-bit) or x86-64 (64-bit) IA-32 (32-bit) or x86-64 (64-bit)
安全启动 有 有 有 有
图片密码 有 有 有 有
开始界面、动态磁帖以及相关效果 有 有 有 有
触摸键盘、拇指键盘 有 有 有 有
语言包 有 有 有 有
更新的资源管理器 有 有 有 有
标准程序 有 有 有 有
文件历史 有 有 有 有
系统的重置功能 有 有 有 有
Play To “播放至”功能 有 有 有 有
Connected standby保持网络连接的待机 有 有 有 有
Windows Update 有 有 有 有
Windows Defender 有 有 有 有
增强的多显示屏支持 有 有 有 有
新的任务管理器 有 有 有 有
ISO 镜像 and VHD 挂载 有 有 有 有
移动通信功能 有 有 有 有
Microsoft 账户 有 有 有 有
Internet Explorer 10 有 有 有 有
SmartScreen 有 有 有 有
Windows 商店 有 有 有 有
Xbox Live 程序 (包括 Xbox Live Arcade) 有 有 有 有
Exchange ActiveSync 有 有 有 有
快速睡眠(snap) 有 有 有 有
VPN连接 有 有 有 有
Device encryption 有 无 无 无
随系统预装的Microsoft Office 有 无 无 无
桌面 部分 有 有 有
储存空间管理(storage space) 无 有 有 有
Windows Media Player 无 有 有 有
Windows Media Center 无 无 需另行添加 无
远程桌面 只作客户端 只作客户端 客户端和服务端 客户端和服务端
从VHD启动 无 无 有 有
BitLocker and BitLocker To Go 无 无 有 有
文件系统加密 无 无 有 有
加入Windows 域 无 无 有 有
组策略 无 无 有 有
AppLocker 无 无 有 有
Hyper-V 无 无 仅64bit支持
Windows To Go 无 无 无 有
DirectAccess 无 无 无 有
分支缓存(BranchCache) 无 无 无 有
以RemoteFX提供视觉特效 无 无 无 有
Metro风格程序的部署 无 无 无 有

下载地址

根据下面的 SHA1 或文件名在网上搜索下载地址,下载完成后验证其 SHA1 即可。

Windows 8 (x86) - DVD (Chinese-Simplified)
文件名: cn_windows_8_x86_dvd_915414.iso
SHA1: 0C4A168E37E38EFB59E8844353B2535017CBC587


Windows 8 (x64) - DVD (Chinese-Simplified)
文件名: cn_windows_8_x64_dvd_915407.iso
SHA1: A87C4AA85D55CD83BAE9160560D1CB3319DD675C


Windows 8 Pro VL (x86) - DVD (Chinese-Simplified)
文件名: cn_windows_8_pro_vl_x86_dvd_917720.iso
SHA1: EEEF3C3F6F05115C7F7C9C1D19D6A6A6418B5059


Windows 8 Pro VL (x64) - DVD (Chinese-Simplified) 推荐
文件名: cn_windows_8_pro_vl_x64_dvd_917773.iso
SHA1: 9C4EC9FC4FB561F841E22256BC9DEA6D9D6611FF


Windows 8 Enterprise (x86) - DVD (Chinese-Simplified)
文件名: cn_windows_8_enterprise_x86_dvd_917682.iso
SHA1: 951565D8579C5912FB4A407B3B9F715FBDB77EFE


Windows 8 Enterprise (x64) - DVD (Chinese-Simplified)
文件名: cn_windows_8_enterprise_x64_dvd_917570.iso
SHA1: 1280BC3A38A7001FDE981FA2E465DEB341478667

激活方式

目前流行 KMSmicro 激活,写此文时的最新版本是 4.0,下载地址网上搜之(或联系我)。

8,063