ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Win32 LoadCursor 光标不换?让走 TaoToken 的 Codex 对着 WM_SETCURSOR 查

Win32 LoadCursor 光标不换?让走 TaoToken 的 Codex 对着 WM_SETCURSOR 查 Win32 里把窗口类的 wc.hCursor 写成 NULL本意是放弃类光标改在 WndProc 的 WM_SETCURSOR 里按 LOWORD(lParam) 判断 HTCLIENT 还是 HTCAPTION再调 SetCursor 切到 IDC_CURSOR1 或 IDC_CURSOR2。可实际跑起来鼠标滑进客户区光标还是系统默认箭头IDC_CURSOR2 像从来没被加载过。这类问题只盯 MSDN 上 LoadCursor、SetCursor 的函数声明很难定位因为返回值语义、DefWindowProc 的兜底处理、resource.h 与 .rc 的 ID 对应、.cur 文件里的 HotSpot任意一个环节偏一点表现都是“光标不换”。本文用 TaoToken 给 Codex 准备好可用的 Key 与 Base URL官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 把 resource.h、WndProc 里 WM_SETCURSOR 的分支、注册窗口类的流程一起交给它做静态核对把“为什么客户区没按 IDC_CURSOR2 切换”拆成可验证的几条。需要说明的是TaoToken 在这里只提供 Key 与 Base URL不参与 Win32 的光标加载与绘制光标最终是否切换仍由你的资源 ID、消息返回值和运行结果决定。一、Win32 光标不换的现场wc.hCursorNULL 与 WM_SETCURSOR 的分工先把原笔记里的关键流程摆清楚否则后面贴给 Codex 的代码片段会缺上下文。资源侧光标资源和图标资源类似都是先添加资源再由代码按 ID 或名字加载HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);hInstance 可以传 NULL此时取系统预定义光标比如 IDC_ARROW、IDC_IBEAM。传自己的实例句柄时lpCursorName 既可以是字符串名也可以是 MAKEINTRESOURCE 包出来的资源 ID。每个 .cur 文件内部还带一个 HotSpot也就是“热区”点击时以这个点为准它和资源 ID 是两回事ID 决定 LoadCursor 取哪张图HotSpot 决定这张图在哪个像素点上生效。窗口类侧注册窗口类时可以给 wc.hCursor 赋一个类光标wc.hCursor LoadCursor(hIns, MAKEINTRESOURCE(IDC_CURSOR1));类光标的作用范围是“默认情况”。当鼠标位于客户区、窗口没有自己处理 WM_SETCURSOR 时DefWindowProc 会拿类光标来设置。把这个字段置成 NULL等于告诉系统“我这里没有默认光标”此时如果 WndProc 里没有把 WM_SETCURSOR 处理干净系统就会用默认箭头兜底。WndProc 侧WM_SETCURSOR 的两个参数要拆开看wParam 是当前光标句柄lParam 的低字 LOWORD(lParam) 是命中测试码HTCLIENT 表示客户区HTCAPTION 表示标题栏还有 HTLEFT、HTBOTTOMRIGHT 等边框区域lParam 的高字 HIWORD(lParam) 是当前鼠标消息 ID。原笔记里典型写法是case WM_SETCURSOR: { HCURSOR hCur LoadCursor(g_hInstance, (char*)IDC_CURSOR2); if (LOWORD(lParam) HTCLIENT) { SetCursor(hCur); return 0; } } break;这段代码有几个地方会在运行时出偏差LoadCursor 的第二个参数在 Unicode 构建下用(char*)IDC_CURSOR2强转并不规范判断只覆盖 HTCLIENT其他命中码直接 break 给 DefWindowProc而类光标已经被置 NULL最关键的是 SetCursor 之后return 0返回值语义与“已处理”不一致。现象就是分支明明进了SetCursor 也调了光标却没按 IDC_CURSOR2 显示。二、TaoToken 前置给 Codex 准备 Key 与 Base URL这一步只做两件事拿到 Key把 Codex 的请求地址指到 TaoToken。不涉及 Win32 的任何资源加载逻辑。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 按页面提示注册账号。进入控制台的 API Keys 页面创建 Key复制出来下面统一写成YOUR_API_KEY。这个 Key 只放在本机环境变量或 Codex 配置里不要写进 .rc、resource.h 或提交到代码仓库。记住 Base URLhttps://taotoken.net/api。注意两点不带/v1不加任何 UTM 参数。Codex 的 config.toml 里填错这两处症状通常是请求直接失败而不是模型回答变差。如果你在团队里统一给 Codex 配接入建议把 Base URL 和 Key 的读取方式固定在文档里避免每个人各写一份。控制台里的 API Keys 页面和接入文档是这一步的主要参考入口排障时先回头确认这两个值比在 Win32 代码里反复猜要快。三、可复制配置config.toml、resource.h 与 WndProc 片段Codex 的配置放在~/.codex/config.tomlWindows 下一般是%USERPROFILE%\.codex\config.toml。下面是一份可复制的骨架模型 ID 按你在 TaoToken 侧实际可用的写model MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api responsesKey 用环境变量传入。Linux/macOSexport TAOTOKEN_API_KEYYOUR_API_KEYWindows PowerShell$env:TAOTOKEN_API_KEYYOUR_API_KEYresource.h 里两个光标 ID 必须是唯一的、且能被 .rc 引用到例如#define IDC_CURSOR1 2001 #define IDC_CURSOR2 2002对应的 .rc 里资源类型写 CURSOR文件名与实际磁盘上的 .cur 一致IDC_CURSOR1 CURSOR cursor1.cur IDC_CURSOR2 CURSOR cursor2.curWndProc 里可以按下面的结构核对注意 WM_SETCURSOR 的返回值和类光标的配合case WM_SETCURSOR: { UINT hit LOWORD(lParam); if (hit HTCLIENT) { HCURSOR hCur LoadCursor(g_hInstance, MAKEINTRESOURCE(IDC_CURSOR2)); if (hCur ! NULL) { SetCursor(hCur); return TRUE; // 表示本条消息已处理不再交给 DefWindowProc 兜底 } } break; // 非客户区交回默认处理前提是类光标有合理值 }如果希望标题栏、边框等非客户区用 IDC_CURSOR1注册窗口类时不要置 NULL而是wc.hCursor LoadCursor(hIns, MAKEINTRESOURCE(IDC_CURSOR1));然后在 HTCLIENT 分支里覆盖成 IDC_CURSOR2。这样即使 WM_SETCURSOR 的某个分支没覆盖到窗口也还有一个可用的类光标不会直接退化成默认箭头。把下面这段提示词连同你的代码片段一起交给 Codex让它做核对而不是自由发挥我在写 Win32 窗口程序wc.hCursor 置为 NULL想在 WM_SETCURSOR 里按 LOWORD(lParam)HTCLIENT 把客户区光标切换到 IDC_CURSOR2但运行时没有切换。 请只依据我贴出的 resource.h、.rc 片段、WndProc 和注册窗口类代码核对 1) WM_SETCURSOR 的返回值语义SetCursor 之后 return 0 与 return TRUE 的差别 2) LoadCursor(g_hInstance, (char*)IDC_CURSOR2) 在 Unicode 构建下是否规范 是否应该改成 MAKEINTRESOURCE 3) wc.hCursorNULL 时 DefWindowProc 对 HTCLIENT 与 HTCAPTION 的处理路径 4) resource.h 中的 IDC_CURSOR1/IDC_CURSOR2 与 .rc 中两条 CURSOR 记录的 ID 是否一一对应HotSpot 是否与预期点击位置一致。 输出最小修改点和需要我手动验证的步骤不要改动无关代码。Codex 在这里的定位是“对着代码逐条核对”结论仍然要你编译运行来确认。四、验证请求与运行结果客户区光标是否按 IDC_CURSOR2 切换先验证 Codex 侧请求确实发出去了。最直接的方式是在终端里用一段极短的对话确认配置生效或者打开模型对话页面选择同一个模型发一条消息能正常返回就说明 Key 与 Base URL 这条链路通了。如果这里报鉴权失败或地址错误先回到 config.toml 检查base_url是否被误写成https://taotoken.net/api/v1或带上了 UTM 参数再检查环境变量名与env_key是否一致。再看 Win32 侧的验证按下面的顺序做不要一上来就怀疑资源文件在 WM_SETCURSOR 的 HTCLIENT 分支里临时加一句输出确认分支确实被执行比如把命中码、LoadCursor 的返回值打印到调试输出。确认 LoadCursor 返回值不是 NULL。如果返回 NULL问题在资源侧与 SetCursor 的调用顺序无关。把返回值从return 0改成return TRUE重新编译运行鼠标移进客户区观察是否按 IDC_CURSOR2 切换。鼠标移到标题栏观察是否按 IDC_CURSOR1 显示如果这里也异常说明类光标或非客户区分支还有问题。如果光标能换但点击位置偏移去检查 .cur 文件里的 HotSpot必要时用光标编辑器调整或者改用 CreateCursor 显式指定 xHotSpot、yHotSpot。只有“分支执行了、LoadCursor 返回非 NULL、返回值语义正确、运行中光标确实切换”这四条同时成立才能说明这段 WM_SETCURSOR 的逻辑跑通了。五、本篇常见错排查WM_SETCURSOR 返回值、LoadCursor、HotSpot、资源 ID按出现频率排一遍。第一WM_SETCURSOR 里 SetCursor 之后return 0。这个返回值会被当成“没有处理”最终仍可能走到 DefWindowProc 的兜底逻辑把刚设置的光标覆盖掉。把 HTCLIENT 分支改为return TRUE是与“已处理”语义一致的写法。这一点在只读函数声明时最容易忽略因为它不报错只影响运行时表现。第二LoadCursor(g_hInstance, (char*)IDC_CURSOR2)的强转。typedef 之后 LPCTSTR 在 Unicode 构建下是const wchar_t*用(char*)转换整数资源 ID 在不同字符集下行为不一致规范写法是MAKEINTRESOURCE(IDC_CURSOR2)或显式调用MAKEINTRESOURCEW。如果这里编译能过但资源取不到LoadCursor 会返回 NULL后续 SetCursor(NULL) 并不会把光标切成 IDC_CURSOR2。第三resource.h 与 .rc 的 ID 对不上。#define IDC_CURSOR2 2002和.rc里的IDC_CURSOR2 CURSOR cursor2.cur必须指向同一个资源记录。常见情况是 .rc 里写的是另一个 ID 或字符串名字而代码用整数 ID 去取取不到就返回 NULL。让 Codex 把两份文件放在一起比对比人眼来回翻要稳。第四HotSpot 与资源 ID 混淆。ID 决定加载哪张光标图HotSpot 决定这张图的热区位置。HotSpot 写偏了不会导致“光标不换”但会出现点击点与光标视觉中心错位看起来像是“换错了光标”。如果 ID 对得上、LoadCursor 返回值正常、返回值也改成了 TRUE但仍觉得不对劲就把检查重点放到 .cur 文件内部的热点上。第五wc.hCursorNULL 之后没有给非客户区兜底。命中码不是 HTCLIENT 时直接 break类光标又是 NULL系统只能用默认箭头。更稳的做法是保留一个类光标作为默认只在 HTCLIENT 分支覆盖或者把所有关心的命中码都显式处理并在处理时返回 TRUE。第六资源文件没有编进工程。修改 .rc 或新增 .cur 之后没有重新编译资源LoadCursor 仍会按旧资源返回。这种情况用调试输出看 LoadCursor 返回值最直接。把以上几条整理成清单后再让 Codex 逐条对照你的代码通常能定位到具体是哪一行导致客户区光标不按 IDC_CURSOR2 切换。六、需要继续排障或长期用 Codex走 API Keys、接入文档与 Coding Plan如果你现在就要把 Key 和 Base URL 配起来继续排查这次光标问题直接进 API Keys 页面创建或复制 Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 配置字段与路径细节对照接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。config.toml 里的base_url仍然只填https://taotoken.net/api不带/v1、不加 UTM。如果你只是想先确认模型侧是否连通不急着动 Win32 工程可以打开模型对话页面发一条消息验证https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。返回正常就说明 Key、Base URL 这条链路没问题剩下的精力全部放回 resource.h、.rc、WM_SETCURSOR 和 HotSpot 上。如果你接下来还要长期用 Codex 查类似 Win32 消息与资源的问题比如字符串资源、加速键资源、WM_COMMAND 的 HIWORD 判定这些可以看一下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 把配置一次性固定下来省去每次重新填 Key 和地址的步骤。回到本篇的结论光标本该切换却没换优先核对 WM_SETCURSOR 的返回值语义、LoadCursor 的资源 ID 与取值方式、以及 wc.hCursorNULL 之后非客户区有没有兜底这三处确认完再去看 .cur 的 HotSpot 和资源文件的编译状态。
返回列表