写了一个右键菜单清理工具以及一些吐槽

注:这是一篇没有什么营养的吐槽文

清理工具

自从一年多前删了一批程序发现右键上下文菜单留下了一批钉子户之后就想着哪天有时间写个工具清理一下。

但是因为比较懒就一直拖到了现在;并且在某天脑袋被门撞了之后想着要不顺带做一个 GUI 吧…

因为核心需要操作注册表,免不了一顿 Win32 API 调用,所以自然用 C++ 比较方便,但是用 C++ 写 GUI 吧,稍有经验的人都知道这是一个蛋疼的事情。

还好我还算比较有毅力:

  1. 用了一个晚上基于 KBase 封装的基础工具写完了核心逻辑
  2. 在网上找了一个比较轻量的 nana-gui 糊了一个周末的 UI

最后算是把成品给做了出来,也确实达成了我的目的,清掉了残留的菜单项。

完整工程链接:the-stupid-context-menu-cleaner

GUI? Thanks, but NO

这部分又名 我为什么不喜欢写 UI。

说起来我的编程生涯是从 GUI 程序开始的。

初中的时候各种折腾 VB6,一直想做个好看、高大上的应用;经常为了追求实现一些炫酷的效果大规模使用当时口口相传的秘术:子类化(sub-classing)。

说是秘术无非是 VB6 本身不支持这样做,强行通过 Win32 API 接管被内部封装的 wndproc(窗口的消息处理过程);记得很容易因为一个不小心连带 IDE 都自动退出。

并且那会儿也没有所谓的 layout management,全靠可视化界面编辑器一个一个拖控件,然后通过手写 on_resize 事件根据窗口大小来调整控件的布局。

即使到了高中开始学 C++ (with classes),也是想着怎么在 MFC 里用那些蹩脚的基础控件和机制把应用做得漂亮点。

直到升入大学并在 C++ 和 system programming 这条歪路上越走越远,GUI 编程对我的吸引开始日益减少;直至今天我对这部分事情完全提不起兴趣。

导致这个变化的原因粗想了一下大概有下面几个。

Read More

Reverse Range Based For Loops

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
template<typename T>
class ReverseIterable {
public:
template<typename U>
explicit ReverseIterable(U&& u)
: iterable_(std::forward<U>(u))
{}

~ReverseIterable() = default;

ReverseIterable(const ReverseIterable&) = delete;

ReverseIterable& operator=(const ReverseIterable&) = delete;

auto begin() noexcept
{
return std::rbegin(iterable_);
}

auto end() noexcept
{
return std::rend(iterable_);
}

private:
T iterable_;
};

template<typename T>
auto MakeReverseIterable(T&& iterable)
{
// 1) if `iterable` is lvalue, then T is deduced as T&
// 2) if `iterable` is rvalue, then T is deduced as T
return ReverseIterable<T>(std::forward<T>(iterable));
}

Read More

禁用某些构造函数

有时候我们希望用更明确的自定义类型取代一些 primitives,依靠类型系统来减少一些人为错误:

1
2
3
4
5
6
7
void Run(WithMultithreading mt, WithAdvancedMode advanced);

// Both of them work like bool
auto mt = WithMultithreading(true);
auto mode = WithAdvancedMode(false);

Run(mt, mode);

类型 WithMultithraedingWithAdvancedMode 用起来很像 bool,但是他们是两个不同的类型,混用会出现编译错误。

1
Run(mode, mt);  // compile failure; type mis-match

不管我们使用 typedef 还是 using,都只能定义 bool 的类型别名;在类型系统看来他们还是一回事。

Read More

Redigo 源码学习:Pipeline

如何使用 pipeline

先来回顾一下如何在 redigo 中使用 pipeline

1
2
3
4
5
6
7
8
c := pool.Get()
defer c.Close()

c.Send("SET", "foo", "bar")
c.Send("GET", "foo")
c.Flush()
c.Receive() // reply from SET
v, err = c.Receive() // reply from GET

核心是 Send — Flush — Receive 三个步骤。

Read More

Error Handling is Operation Cancellation

最近看了这篇文章有一种顿悟感,想着写点总结加深理解。

如果嫌原文太长可以直接看这篇总结;不过别人咀嚼过的不一定适合你,所以还是推荐一块把原文也看了😁。

Operation Cancellation

假设一个函数 foo() 中的某个操作发生了错误,并且后续操作直接或间接地依赖当前操作的正确行为;那么,不管使用何种错误处理/汇报手段,这里都需要 (1) 中止后续操作并 (2) 向上汇报错误。

这里称这种行为为 operation cancellation

Read More

Python fileinput 换行编码问题

昨晚抽了个时间想修一下 anvil 的这个 issue

根据之前的代码实现,我有 99.99% 的把握换行符被替换成 CRLF 是使用了 fileinput 原地修改了文件导致的。

那段修改的代码的一个等价实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import shutil
import fileinput
import sys

def poc():
orig_name = 'orig.txt'
new_name = 'new.txt'

shutil.copy(orig_name, new_name)

with fileinput.FileInput(new_name, inplace=True) as f:
for line in f:
line = '-> ' + line
print(line, end='')

orig.txt 是一个模板文件,它会被拷贝到指定目录变成一个新文件 new.txt,并修改文件内容。

Read More

Redigo 源码学习:阻塞等待连接可用

通过连接池的设计了解如何回收连接到连接池以及从连接池复用连接后,可以回过头来研究一下 Redigo 支持的阻塞等待可用连接的设计与实现。

通过设置 Pool.Wait == true 之后如果当前连接池满了, Pool.Get() 不会返回连接池耗尽错误,而是阻塞在调用上,直到超时或者存在可用连接才会返回。

这个属于经典的 resource counting 问题,并且最大的 resource count 由 Pool.MaxActive 决定。

Read More