首页

不要被各种专业术语吓倒  

有一个东西,是如此奇妙,今天我们需要讲讲。 在不同的函数中,这个东西有着不同的名字,但实际它都是同一个东西。 例如,RegisterWaitForSingleObject 这个 API,它的原型如下: BOOL RegisterWaitForSingleObject( [out] PHANDLE phNewWaitObject, [in] HANDLE hObject, [in] WAITORTI...

VS2022 17.8: Build Insights 中的函数视图  

简述 今天,我们很高兴的宣布在 Visual Studio 中为 Build Insights 新增了一项新功能:函数视图(Functions View)。 此功能在 Visual Studio 2022 v17.8 版本中可用。函数视图可以为你的代码库中的函数和强制内联(Forceinlines)提供更加具有深度的洞察力。 我们衷心感谢开发者社区,特别是我们的游戏工作室合作伙伴,他们积极地提供了...

为什么鼠标按键释放后才执行对应的动作?  

如果你留心观察的话,你会发现这样一个事实:大部分的软件的用户体验中,一般都是在鼠标按键释放后,才会执行相应的动作,而不是按下的时候。例如,当我们按下开始菜单的时候,不会有任何动作发生,只有当我们释放开始菜单的时候,才会弹出开始菜单。(可能有一些例外的情况,例如在文本编辑器里打字就没有遵循这个原则) 为什么大部分的软件都在操作释放的时候才会执行动作呢? 首先,等待鼠标操作完成(按键释放)意味着你为用...

在列表控件上显示提示信息  

当我们在实现列表控件上的提示信息的时候,我们需要处理的一个难点是处理列表条目的折叠和展开这两种情况。 所谓列表条目的折叠,即在大图标模式(Large Icon Mode)下,列表条目的文字过长而被截断的情况。当用户选择这个条目后,条目的完整文字将会被显示,这个过程就是所谓的展开过程。 在我们的例子代码中,添加如下的代码,就可以轻松处理这种情况了。 代码解析 我们先创建了一个列表控件并启用了列表的...

调用 LeaveCriticalSection 出现无效句柄异常  

从内部的视角看,一个临界区是一套计数器和标志位的集合,也可能是一个事件对象。 (请注意,临界区的内部结构随时可能更改,事实上,它在 Windows XP 和 Windows 2003 之间发生了变化。因此,此处提供的信息仅用于故障排除和调试目的,不用于生产用途。) 只要没有争用,计数器和标志位就足够了,因为没有人必须等待临界区(因此,当临界部分区时,没有人必须被唤醒)。 如果一个线程需要被阻塞,因...

深入了解鼠标光标的设置过程  

有一位读者问了这样一个问题: “为什么鼠标光标的设定绑定在窗口类,而不是窗口上?” 这个问题隐含地假设了光标与窗口类相关联。虽然每个窗口类都有一个关联的光标,但决定使用哪个光标的是窗口。 光标设置过程在 WM_SETCURSOR 消息的文档中进行了描述,请看如下: =================================== DefWindowProc 函数在处理...

如何将一个 HRESULT 转换为 Win32 错误码?  

地球人都知道,可以使用 HRESULT_FROM_WIN32 这个宏将一个 Win32 错误码转换为一个 HRESULT,但是如何将一个 HRESULT 转换为 Win32 错误码呢? 让我们先看看 HRESULT_FROM_WIN32 这个宏的定义: ============================================================= #define HRE...

思维调试:调用ShellExecute后为什么程序没有启动  

今天的问题来自我的一位读者: “如果我在命令行下启动我的程序,一切都是正常的。但是,当我在代码中调用 ShellExecuteEx 来启动程序时,好像什么都没有发生,这是为什么?” 在我问下面的第二个能给出答案的问题之前,你可以自己思考下大概问题的原因出在哪里? 下面是来自另外一个读者的问题反馈,它和上面这个十分类似: “我正在尝试使用 ShellExecute...

用户自定义消息及层次划分  

有些人对术语 WM_USER 表示消息范围基的名称有不同的意见,因为 WM_USER 是由窗口类的实现者来定义的。他们抱怨的是,用户不能使用它们,因为它们属于窗口类定义的一部分。 但是,问题是,”这里的用户是谁?” 换句话说,当我们说”用户自定义”这个词的时候,做自定义操作的这个用户到底是指谁? 在上面这个问题中,总共有四个不同的组件涉及其中,每个组...

跨模块边界分配和释放内存  

我想,有一条编程铁律已经深深的刻入到你的头脑中了:使用成套的函数来分配和释放内存,例如,如果使用 LocalAlloc 分配内存,则应该使用 LocalFree,类似的例子还有:GlobalAlloc 对应 GlobalFree,new [] 对应 delete []。 但这条规则还有更深层次的潜规则。 如果你提供了一个函数分配了一段内存并返回了数据,则调用者必须知道如何释放该内存。 实现这个目标...