新版本的 C# 特性需要新版本的 Visual Studio 的支持。不过,如果你不介意修改项目的话,你也能在低版本的 Visual Studio 中获得高版本的 C# 语言支持了。 而使用 Microsoft.Net.Compilers 这款 NuGet 包就可以做到。 不同 Visual Studio 原生支持的 C# 版本 Visual Studio 每一次的重大发布都带...
制作一个极简的 .NET 客户端应用自安装或自更新程序
本文主要说的是 .NET 客户端应用,可以是只能在 Windows 端运行的基于 .NET Framework 或基于 .NET Core 的 WPF / Windows Forms 应用,也可以是其他基于 .NET Core 的跨平台应用。但是不是那些更新权限受到严格控制的 UWP / iOS / Android 应用。 本文将编写一个简单的程序,这个程序初次运行的时候会安装自己,如果已...
WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)
WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验。如果希望做不同线程的 UI,大家也会想到使用另一个窗口来实现,让每个窗口拥有自己的 UI 线程。然而,就不能让同一个窗口内部使用多个 UI 线程吗? 阅读本文将收获一份 Win32 函数 SetParent 及相关函数的使用方法。 WPF 同一个窗口中跨线程访问 UI 有多种方法: 使用...
应用程序清单 Manifest 中各种 UAC 权限级别的含义和效果
如果你的程序对 Windows 运行权限有要求,那么需要设置应用程序清单。本文介绍如何添加应用程序清单,并解释其中各项 UAC 权限设置的实际效果。 阅读本文之前,你可能需要了解如何创建应用程序清单文件。阅读我的另一篇博客可以了解: 如何创建应用程序清单文件 App.Manifest,如何创建不带清单的应用程序 - 吕毅 各种不同的 UAC 清单选项 从默认生成的应用...
Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)
Windows 系统上的任务管理器进化到 Windows 10 的 1809 版本后,又新增了几项可以查看的进程属性。 本文介绍可以使用任务管理器查看的各种进程属性。 如何查看进程的各种属性 在任务栏上右键,选择“任务管理器”;或者按下 Ctrl + Shift + Esc 可以打开任务管理器。如果你的电脑死掉了,也可以按 Ctrl + Alt + Del 再选择任务管理器打开...
如何创建一个基于 .NET Core 3 的 WPF 项目
在 Connect(); 2018 大会上,微软发布了 .NET Core 3 Preview,以及基于 .NET Core 3 的 WPF;同时还发布了 Visual Studio 2019 预览版。不过 Visual Studio 2019 的预览版中并没有携带 WPF on .NET Core 3 的模板,于是新建项目的时候并不能快速创建一个基于 .NET Core 3 的 WPF 项...
Windows 的 UAC 设置中的通知等级实际上只有两个档而已
Windows 系统中的 UAC 设置界面有四种不同的选项可以选,但实际上真正有意义的只有两个选项。 本文将介绍 UAC 这四个档设置的区别,帮助你合理的设置你的电脑。 UAC 设置界面 在 Windows 10 任务栏的搜索框中输入 uac 可以直接打开 UAC 设置界面。 下图是“用户账户控制设置”界面,想必小伙伴们应该已经很熟悉了。它有四个档: 始终通知 当...
Windows 中的 UAC 用户账户控制
阅读本文,你可以初步了解 Windows 上的 UAC 用户账户控制机制。本文不会涉及到 UAC 的底层实现原理和安全边界问题。 用户账户 在 Windows 中有多种不同的账户: SYSTEM Administrators 用户组 Administrator 管理员账户 Users 用户组 ...
Windows 下使用 runas 命令以指定的权限启动一个进程(非管理员、管理员)
在默认情况下,Windows 系统中启动一个进程会继承父进程的令牌。如果父进程是管理员权限,那么子进程就是管理员权限;如果父进程是标准用户权限,那么子进程也是标准用户权限。 我们也知道,可以使用一些方法为自己的应用程序提权。但是有没有方法可以任意指定一个权限然后运行呢?本文将介绍 Windows 下指定权限运行的做法。 runas 命令 runas 是 Windows 系统上自...
启用 Windows 审核模式(Audit Mode),以 Administrator 账户来设置电脑的开箱体验
在你刚刚安装完 Windows,在 Windows 开箱体验输入以创建你的用户账户之前,你可以按下 Ctrl + Shift + F3 来进入审核模式。 本文将介绍审核模式。 OOBE OOBE,Out-of-Box Experience,开箱体验。对于 Windows 系统来说,就是当你买下电脑回来,兴奋地打开电脑开机后第一个看到的界面。 具体来说,就是设置你的账号以及各种...
如何创建应用程序清单文件 App.Manifest,如何创建不带清单的应用程序
如果你的程序对 Windows 运行权限有要求,那么需要设置应用程序清单。本文介绍如何添加应用程序清单,并解释其中各项权限设置的实际效果。 嵌入带默认设置的清单 对于 WPF 和 Windows Forms 程序,如果你什么都不做,那么就已经嵌入了一个带有默认设置的清单。 下图可以在 Visual Studio 中的项目上右键属性插件。 新建一个自定义的清单文件 在项目...
在有 UI 线程参与的同步锁(如 AutoResetEvent)内部使用 await 可能导致死锁
AutoResetEvent、ManualResetEvent、Monitor、lock 等等这些用来做同步的类,如果在异步上下文(await)中使用,需要非常谨慎。 本文将说一个在同步上下文中非常常见的一种用法,换成异步上下文中会产生死锁的问题。 一段正常的同步上下文的代码 先看看一段非常简单的代码: private void OnLoaded(object sender,...
.NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
一个简单的 Task 不会消耗多少时间,但如果你不合适地将 Task 转为同步等待,那么也可能很快耗尽线程池的所有资源,出现类似死锁的情况。 本文将以一个最简单的例子说明如何出现以及避免这样的问题。 耗时的 Task.Run 谁都不会认为 Task.Run(() => 1) 这个异步任务执行会消耗多少时间。 但实际上,如果你的代码写得不清真,它真的能消耗大量的时间,这种...
在编写异步方法时,使用 ConfigureAwait(false) 避免使用者死锁
我在 使用 Task.Wait()?立刻死锁(deadlock) 一文中站在类库使用者的角度看 async/await 代码的死锁问题;而本文将站在类库设计者的角度来看死锁问题。 阅读本文,我们将知道如何编写类库代码,来尽可能避免类库使用者出现那篇博客中描述的死锁问题。 可能死锁的代码 现在,我们是类库设计者的身份,我们试图编写一个 RunAsync 方法用以异步执行某些操作。...
将 async/await 异步代码转换为安全的不会死锁的同步代码(使用 PushFrame)
在 async/await 异步模型(即 TAP Task-based Asynchronous Pattern)出现以前,有大量的同步代码存在于代码库中,以至于这些代码全部迁移到 async/await 可能有些困难。这里就免不了将一部分异步代码修改为同步代码。然而传统的迁移方式存在或多或少的问题。本文将总结这些传统方法的坑,并推出一款异步转同步的新方法,解决传统方法的这些坑。 ...
使用 Task.Wait()?立刻死锁(deadlock)
最近读到一篇异步转同步的文章,发现其中没有考虑到异步转同步过程中发生的死锁问题,所以特地在本文说说异步转同步过程中的死锁问题。 文章作者 林德熙 已经修复了描述: win10 uwp 异步转同步 什么情况下会产生死锁? 调用 Task.Wait() 或者 Task.Result 立刻产生死锁的充分条件: 调用 Wait() 或 Result 的代码位于 UI 线程...
不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 Lazy 中导致死锁
WPF 中为了 UI 的跨线程访问,提供了 Dispatcher 线程模型。其 Invoke 方法,无论在哪个线程调用,都可以让传入的方法回到 UI 线程。 然而,如果你在 Lazy 上下文中使用了 `Invoke`,那么当这个 `Lazy` 跨线程并发时,极有可能导致死锁。本文将具体说说这个例子。 一段死锁的代码 请先看一段非常简单的 WPF 代码: private Laz...
C#/.NET 如何结束掉一个进程
本文介绍如何结束掉一个进程。 结束掉特定名字的进程 ProcessInfo 中有 Kill 实例方法可以调用,也就是说如果我们能够拿到一个进程的信息,并且对这个进程拥有访问权限,那么我们就能够结束掉它。 使用 Process.GetProcessesByName(processName) 可以按照名字拿到进程信息。于是我们可以使用这个方法杀掉具有特定名称的进程。 privat...
让你的 VSCode 具备调试 C# 语言 .NET Core 程序的能力
如果你是开发个人项目,那就直接用 Visual Studio Community 版本吧,对个人免费,对小团体免费,不需要这么折腾。 如果你是 Mac / Linux 用户,不想用 Visual Studio for Mac 版;或者不想用 Visual Studio for Windows 版那么重磅的 IDE 来开发简单的 .NET Core 程序;或者你就是想像我这么折腾,那我们就开...
手工编辑 tasks.json 和 launch.json,让你的 VSCode 具备调试 .NET Core 程序的能力
如果 C# for Visual Studio Code 没有办法自动为你生成正确的 tasks.json 和 launch.json 文件,那么可以考虑阅读本文手工创建他们。 前期准备 你需要安装 .NET Core Sdk、Visual Studio Code 和 C# for Visual Studio Code,然后打开一个 .NET Core 的项目。如果你没有准备,请...
自然码的形码
使用拼音/双拼输入法,如果你的打字速度还需要继续提升,那么就不应该再不断地看着候选框打字了。使用双拼形码可以规避相当多字词的选字。 本文整理自然码的形码,然后附带一张我自己制作的自然码形码的键盘图。 输入法的选择 目前各种双拼输入法中,辅码最接近自然码形码的,是手心输入法。所以我选用了手心输入法并重新训练了词库。 这款输入法与 360 有点关系,不过很不 360。这让我有点犹...
在 Visual Studio Code 中添加自定义的代码片段
无论是那个编辑器,如果能够添加一些自定义代码片段,能够大大提升代码的输入效率。 本文介绍如何在 Visual Studio Code 中添加自定义代码片段。 Visual Studio Code 的代码片段设置 你可以在 Visual Studio Code 的菜单中找到代码片段的设置入口,在 File -> Preferences -> User Snippets...
解决 mklink 使用中的各种坑(硬链接,软链接/符号链接,目录链接)
通过 mklink 命令可以创建文件或文件夹的链接,而这种链接跟快捷方式是不一样的。然而我们还可能会遇到其使用过程中的一些坑,本文将整理这些坑并提供解决方法。 0x00 背景介绍:mklink mklink 可以像创建快捷方式一样建立文件或文件夹的链接,但不同于快捷方式的是,mklink 创建的链接绝大多数程序都不会认为那是一个链接,而是一个实实在在的文件或文件夹。 例如,为 ...
.NET 中的轻量级线程安全
对线程安全有要求的代码中,通常会使用锁(lock)。自 .NET 诞生以来就有锁,然而从 .NET Framework 4.0 开始,又诞生了 6 个轻量级的线程安全方案:SpinLock, SpinWait, CountdownEvent, SemaphoreSlim, ManualResetEventSlim, Barrier。 类型 SpinLock, SpinWait Sp...
UI 设计中的视觉无障碍设计(色盲眼中的世界以及 UI 使用体验)
我给博客改了主题色,从 这样的 改成了 这样的;然而我问小伙伴看看效果他却并没有发现改变。 红绿色盲在亚洲人中占比,男性约 5%,女性则小得多。也就是说,就算仅考虑为国内用户开发应用,这也是很大的一部分用户了。 本文将通过更加了解色盲(Color Blindness)来指导我们为更多用户提供更好的 UI 设计。 没有色盲模拟器 大多数想理解色盲眼中世界的人可能会考虑“色盲...
C#/.NET 中的契约式编程,以及 ReSharper 为我们提供的契约特性
将文档放到代码里面,文档才会及时地更新! 微软从 .NET Framework 4.0 开始,增加了 System.Diagnostics.Contracts 命名空间,用来把契约文档融入代码。然而后面一直不冷不热,Visual Studio 都没天然支持。 ReSharper 也提供了 ReSharper Annotations,在 ReSharper 插件工作的情况下能够进行...
我收集的各种公有 NuGet 源
本文收集我发现的各种公共 NuGet 源。 如何添加本文介绍的 NuGet 源? 请参见: 全局或为单独的项目添加自定义的 NuGet 源 官方 NuGet 源 官方源 https://api.nuget.org/v3/index.json 官方离线本地源 C:\Program Files (x8...
在 csproj 文件中使用系统环境变量的值(示例将 dll 生成到 AppData 目录下)
Windows 系统以及很多应用程序会考虑使用系统的环境变量来传递一些公共的参数或者配置。Windows 资源管理器使用 %var% 来使用环境变量,那么我们能否在 Visual Studio 的项目文件中使用环境变量呢? 本文介绍如何在 csproj 文件中使用环境变量。 遇到的问题 在 Windows 资源管理器中,我们可以使用 %AppData% 进入到用户的漫游路径。我...
为 WPF 程序添加 Windows 跳转列表的支持
Windows 跳转列表是自 Windows 7 时代就带来的功能,这一功能是跟随 Windows 7 的任务栏而发布的。当时应用程序要想用上这样的功能需要调用 shell 提供的一些 API。 然而在 WPF 程序中使用 Windows 跳转列表功能非常简单,在 XAML 里面就能完成。本文将介绍如何让你的 WPF 应用支持 Windows 跳转列表功能。 一个简单的跳转列表程...
Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新)
程序如何自己更新自己呢?你可能会想到启动一个新的程序或者脚本来更新自己。然而 Windows 操作系统允许一个应用程序在运行期间修改自己的名称甚至移动自己到另一个文件夹中。利用这一点,我们可以很简单直接地做程序的 OTA 自动更新。 本文将介绍示例程序运行期间改名并解释其原理。 在程序运行期间手工改名 我们写一个简单的程序。 将它运行起来,然后删除。我们会发现无法删除它。...