当前位置: 首页 > news >正文

古神的迷踪--Win32窗户探索记录

我需要一个窗户

我现在位于 win32 的世界,

#include <Windows>

创世之初

我需要一个窗户,
我向她祈求一个窗户,然后将其安放在我的 class 深处:

class my_Win32Window {
public:}

我愿意献出我的所有,来换取一个窗户:

LPCWSTR wndClassName = L"my_win32Window_example";
int x = 0, y = 0; // 位置
int w = 800, h = 600; // 尺寸
LPCWSTR windowName = L"我的窗户"; // 名称
HINSTANCE hInst = GetModuleHandle(nullptr); // 当前程序的实例, 如使用 WinMain 则由主函数传入

我想应该足够了吧,她说那 WndProc 呢,我瞬间石化,我突然发现我居然没有办法弄到这个重要的东西,
(解释:因为 WndProc 的类型为函数指针, 必须为普通函数或静态成员函数, 而不能是自带 this 的普通成员函数)

好在姐姐体量我,她借给我一个 静态成员函数 类型的,并嘱咐我不用还了:

static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {}

我感动的稀里哗啦,小心翼翼的把 wndProc 收在 my_Win32Window 中,
她踮着脚,在高高的柜子顶上翻找,拿下来一张古老的残卷,记录着属于古神的召唤仪式:

// 创建窗口
HWND createWindow(int x, int y, int w, int h, LPCWSTR windowName, HINSTANCE hInst, WNDPROC wndProc, LPVOID createLongParam = nullptr) {// 注册窗口类WNDCLASS wc = {};wc.lpfnWndProc = wndProc; // 窗口处理过程函数wc.hInstance = hInst; // 当前程序实例(窗口父级)wc.lpszClassName = wndClassName; // 窗口类名if (RegisterClass(&wc) == 0) { throw(GetLastError()); } // 重复注册: 同 hInst 且同名 会判定为重复注册    // 创建窗口hWnd = CreateWindow(wndClassName, // 窗口类名称windowName, // 窗口标题	WS_OVERLAPPEDWINDOW, // 窗口风格,或称窗口格式x, y, w, h, // 窗口位置和尺寸nullptr, // 父窗口句柄nullptr, // 窗口菜单句柄hInst, // 程序实例句柄createLongParam// 创建参数);if (hWnd == nullptr) { throw(GetLastError()); }return hWnd;
}

我依次摆好祭品,
我问她 createLongParam 是什么,她跟我说先可以空着,一会我就会懂的,
哦,我念动古老的咒语,伟大的远古的巨硬之神,赐予我窗户吧……

auto hWnd = createWindow(x, y, w, h, windowName, hInst, wndProc);

一个发光的神器到了我手中,
她说,那是我和古神的契约,古神的力量,将以此为凭证,

举起神器念动咒语,远古的魔力将为我而燃烧……

void Show(HWND hWnd) {ShowWindow(hWnd, SW_SHOWDEFAULT); // 显示窗口
}
void Hide(HWND hWnd) {ShowWindow(hWnd, SW_HIDE); // 隐藏窗口
}// ============================================================================void SetTitle(HWND hWnd, const std::wstring WndName) {SetWindowText(hWnd, WndName.c_str());
}
std::wstring GetTitle(HWND hWnd) {int titleLength = GetWindowTextLength(hWnd); // 获取标题长度if (titleLength == 0) {if (GetLastError() != ERROR_SUCCESS) { throw("Error occur while GetWindowTextLength()"); }return L"";}std::wstring title(L' ', titleLength + 1); // 预留终止符空间int copiedLength = GetWindowText(hWnd, &title[0], titleLength + 1 );if (copiedLength == 0) {if (GetLastError() != ERROR_SUCCESS) { throw("Error occur while GetWindowText()"); }return L"";}title.resize(copiedLength);return title;
}// ============================================================================void SetIcon(HWND hWnd, const std::wstring IconName) { // 从文件加载图标(过时的实现)SetClassLong(hWnd, GCLP_HICON, (LONG)(HICON)LoadImage(hInst, IconName.c_str(), IMAGE_ICON, 32, 32, LR_LOADFROMFILE));
}// ============================================================================void SetPosAndSize(HWND hWnd, int x, int y, int w, int h) { // 设置位置尺寸SetWindowPos(hWnd, nullptr, x, y, w, h, SWP_FRAMECHANGED);
}
void GetPosAndSize(HWND hWnd, int& x, int& y, int& w, int& h) { // 获取位置尺寸RECT r;GetWindowRect(hWnd, &r);x = r.left; y = r.top; w = r.right - r.left; h = r.bottom - r.top;
}// ============================================================================void SetMousePos(HWND hWnd, int x, int y) { // 设置光标位置POINT p{x, y};ClientToScreen(hWnd, &p); // 窗口客户区坐标转为屏幕坐标SetCursorPos(p.x, p.y); // 设置光标位置
}
void GetMousePos(HWND hWnd, int& x, int& y) { // 设置光标位置POINT p;GetCursorPos(&p); // 基于屏幕坐标获取光标位置ScreenToClient(hWnd, &p); // 屏幕坐标转窗口客户区坐标x = p.x; y = p.y;
}
void ConfineCursor(bool isConfine) { // 捕获光标,开启捕获后光标不会移动到窗口外cursorConfine = isConfine;if (isConfine == true) {RECT rect;GetClientRect(hWnd, &rect);MapWindowPoints(hWnd, nullptr, (POINT*)(&rect), 2);ClipCursor(&rect);} else {ClipCursor(nullptr);}
}

灵魂注入

已经有了一个窗户,但是,这个窗户是没有灵魂的,为什么呢, 仙凡有别!
我拿出神器 WndProc ,陷入了深深的迷惘……
WndProc静态成员函数 ,是神器,而我只是一介凡夫,
我可以感受到祂的存在,而祂却感受不到我的存在:

class my_Win32Window {int me = 0; // 我static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {me = 0; // 错误,非静态成员引用必须与特定成员相对}
}

迷惘的我,没有注意到翻箱倒柜的她,直到她把一张古老的残卷又铺开在我的面前,我才回过神来,
她问我是否知道窗户的灵魂是何物,我说那当然是知道的,那是无敌的古老分支大王 switch-case

LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {switch (msg) {case WM_XX1 : ...; break;case WM_XX2 : ...; break;...}
}

她告诉我说,这张残卷上记载着一种古老的秘术,能把我的灵魂传送到另一个世界,
可以通过这种秘术让 wndProc 感知到我的存在,进而建立灵魂的链接:

if (msg == WM_NCCREATE) {CREATESTRUCTW* pCreateParams = (CREATESTRUCTW*)(lParam); // 创建窗口时传入的参数包pWnd = (Win32Window*)(pCreateParams->lpCreateParams);
}

原来,古神在建造每一扇窗户的时候,都在暗中留下了笔记,
而献祭给古神的祭品中,最后一项可献祭任意物品,也可为空,
createLongParam ,古神并不关心这项祭品,故可以不献祭,

她说,但是如果把我的灵魂作为这最后一项祭品献祭,
我的灵魂就会出现在古神的笔记中,
进而 wndProc 就可感知到我的存在:

class my_Win32Window {
public:my_Win32Window() {hWnd = createWindow(..., this); // 献祭我的灵魂}LRESULT CALLBACK my_wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // 凡器 `my_wndProc`// }static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // 神器 `wndProc`static my_Win32Window* wnd_ptr;if (msg == WM_NCCREATE) {CREATESTRUCTW* pCreateParams = (CREATESTRUCTW*)(lp); // 查找到古神的笔记wnd_ptr = (my_Win32Window*)(pCreateParams->lpCreateParams); // 感知到我的灵魂}if (wnd_ptr != nullptr) {wnd_ptr->my_wndProc(hWnd, msg, wp, lp) // 链接到我的灵魂}}
}

古老的魔力熊熊燃烧,我看到神器在向我招手……
后来姐姐说其实我手上的 hWnd 也可以代为传递我的灵魂,那是一种更古老的秘法:

static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // 可应对多窗口的改进型if (msg == WM_NCCREATE) { // 窗口创建时:从祭品中提取灵魂CREATESTRUCTW* pCreateParams = (CREATESTRUCTW*)(lp); // 查找到古神的笔记wnd_ptr = (my_Win32Window*)(pCreateParams->lpCreateParams); // 感知到我的灵魂SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)(wnd_ptr)); // 然后将其连接到 hWnd} else {wnd_ptr = (my_Win32Window*)(GetWindowLongPtr(hWnd, GWLP_USERDATA)); // 通过 hWnd 感知到我的灵魂wnd_ptr->my_wndProc(hWnd, msg, wp, lp) // 链接到我的灵魂}
}

灵魂注入的琐事

事到如此,已经大功告成了,(喜)
于是姐姐也忙她的去了不再理我了,(悲)
之后就是填充灵魂物质的琐碎事了,就跟砌墙一样,纯体力活:

#define LOWORDINT(n) ((int)((signed short)(LOWORD(n))))
#define HIWORDINT(n) ((int)((signed short)(HIWORD(n))))
LRESULT CALLBACK my_wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { // 凡器 `my_wndProc`// ---- 消息处理过程 ----switch (msg) {case WM_CLOSE:PostQuitMessage(0); // 退出, 关闭窗口return 0;case WM_KILLFOCUS: // 窗口失去焦点// ...break;case WM_SETFOCUS:// ...break;case WM_ACTIVATE: // 窗口被激活或失活if (wp & WA_ACTIVE) {// 窗口被激活} else {// 窗口被失活}break;case WM_SIZE: // 窗口尺寸改变, lp 低位表示客户区的宽, 高位表示客户区的长int w = LOWORD(lp);int h = HIWORD(lp);// ...break;case WM_MOVE: // 窗口移动int x = LOWORD(lp);int y = HIWORD(lp);// ...break;case WM_PAINT: // 重绘// ...break;/*********** INPUT MESSAGES 输入消息 ***********/case WM_SYSKEYDOWN:case WM_KEYDOWN:if ((lp & 0x40000000)) { // lp 包含很多信息, 此处为排除重复按键// 按键被按下, keyCode = wp;}break;case WM_SYSKEYUP:case WM_KEYUP:// 按键被弹起, keyCode = wp;break;case WM_CHAR:// 字符输入, inputChar = wpbreak;/************* MOUSE MESSAGES 鼠标消息 ****************/case WM_MOUSEWHEEL:// 鼠标滚轮滚动, 滚动距离为 GET_WHEEL_DELTA_WPARAM(wp) / WHEEL_DELTA// lp 低位表示鼠标位置 x, 高位表示鼠标位置 ypWnd->inputEvent(inputType::MouseWheelAndMove, GET_WHEEL_DELTA_WPARAM(wp) / WHEEL_DELTA, LOWORDINT(lp), HIWORDINT(lParam));break;case WM_MOUSEMOVE:// 鼠标移动, lp 低位表示鼠标位置 x, 高位表示鼠标位置 ybreak;case WM_LBUTTONDOWN:case WM_LBUTTONDBLCLK:case WM_RBUTTONDOWN:case WM_RBUTTONDBLCLK:case WM_MBUTTONDOWN:case WM_MBUTTONDBLCLK:case WM_LBUTTONUP:case WM_RBUTTONUP:case WM_MBUTTONUP:// 鼠标按键事件, lp 低位表示鼠标位置 x, 高位表示鼠标位置 y// 按键码为 VK_LBUTTON, VK_MBUTTON, VK_RBUTTONbreak;default:return DefWindowProc(hWnd, msg, wp, lp);}
}

终焉亦初

随着一切的就绪,命运的齿轮已悄悄啮合,
当先知的预言降临,天地万物将展开宿命的循环……

int MainLoop() {int ret = 0;MSG msg;while (true) { // 主循环if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // 消息处理if (msg.message == WM_QUIT) {ret = (int)msg.wParam;break; // 跳出主循环}TranslateMessage(&msg); // 消息处理DispatchMessage(&msg);}// ==== 更新渲染 等 其他处理 ====}return ret;
}

简单示例(半成)

#include <Windows.h>
#include <stdexcept>
#include <string>
#include <cstdint>
#include <functional>class example_easyInput {friend class my_Win32Window;
public:bool KeyDown(int keycode);bool KeyUp(int keycode);bool IsKeyPressed(int keycode);
private:void keyDownEvent(unsigned char key);void keyUpEvent(unsigned char key);void mouseKeyDownEvent(int pos_x, int pos_y, unsigned char key);void mouseKeyUpEvent(int pos_x, int pos_y, unsigned char key);void mouseMoveEvent(int pos_x, int pos_y);void mouseWheelEvent(int wheelDiff);
};class example_callbacks {
public:example_callbacks() {UpdateFunc = [](float dt) {return true; };ExitFunc = []() {return true; };FocusLostFunc = []() {};FocusGainFunc = []() {};RenderFunc = []() {};}std::function<bool(float)> UpdateFunc; // 更新回调, 返回 false 退出循环, 传入上帧运行时间, 更新并生成渲染目标数据std::function<bool()> ExitFunc; // 关闭回调, 窗口试图被关闭时触发, 返回 true 将关闭窗口并退出std::function<void()> FocusLostFunc; // 窗口失去焦点std::function<void()> FocusGainFunc; // 窗口获得焦点std::function<void()> RenderFunc; // 渲染回调
};// 核心窗口类:封装Win32窗口的创建、消息处理和常用操作
class my_Win32Window {
private:// 窗口核心属性HWND hWnd = nullptr;          // 窗口句柄(契约凭证)HINSTANCE hInst = nullptr;    // 程序实例句柄int x = 0, y = 0;             // 窗口位置int w = 800, h = 600;         // 窗口尺寸LPCWSTR windowName = L"我的窗户"; // 窗口名称static constexpr LPCWSTR wndClassName = L"MyWin32WindowClass"; // 窗口类名(唯一标识)bool isActivate = true;bool cursorConfine = false;   // 光标是否被限制在窗口内// 静态窗口过程(神器):Win32要求必须是静态/全局函数static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {// 窗口创建时:从创建参数中提取实例指针(绑定灵魂)if (msg == WM_NCCREATE) {CREATESTRUCTW* pCreateParams = reinterpret_cast<CREATESTRUCTW*>(lp);my_Win32Window* wnd_ptr = reinterpret_cast<my_Win32Window*>(pCreateParams->lpCreateParams);// 将实例指针关联到窗口句柄(更健壮的方式,替代static)SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(wnd_ptr));}// 从窗口句柄获取实例指针(兼容多窗口场景)else {my_Win32Window*  wnd_ptr = reinterpret_cast<my_Win32Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));// 调用实例的消息处理函数(注入灵魂)if (wnd_ptr != nullptr) {return wnd_ptr->my_wndProc(hWnd, msg, wp, lp);}}// 默认消息处理(无实例时)return DefWindowProc(hWnd, msg, wp, lp);}// 实例消息处理(凡器):真正的业务逻辑处理LRESULT my_wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {// 简化宏定义(处理高低位)
#define LOWORDINT(n) static_cast<int>(static_cast<SHORT>(LOWORD(n)))
#define HIWORDINT(n) static_cast<int>(static_cast<SHORT>(HIWORD(n)))switch (msg) {case WM_CLOSE:if (Callbacks.ExitFunc() == true) { PostQuitMessage(0); } // 退出, 关闭窗口return 0;case WM_KILLFOCUS: // 窗口失去焦点Callbacks.FocusLostFunc();isActivate = false; // 窗口不活动break;case WM_SETFOCUS:Callbacks.FocusGainFunc();isActivate = true; // 窗口活动break;case WM_ACTIVATE: // 窗口被激活或失活if (wp & WA_ACTIVE) { // 激活Callbacks.FocusGainFunc();isActivate = true;} else { // 失活Callbacks.FocusLostFunc();isActivate = false;}if (cursorConfine) { // 如果设置了捕获鼠标则捕获ConfineCursor(isActivate);}break;case WM_SIZE: // 尺寸改变 lParam 低位表示客户区的宽,高位表示客户区的长w = LOWORD(lp);h = HIWORD(lp);break;case WM_MOVE: // 窗口移动x = LOWORD(lp);y = HIWORD(lp);break;case WM_PAINT: // 重绘break;/*********** INPUT MESSAGES 输入消息 ***********/case WM_SYSKEYDOWN:case WM_KEYDOWN:if (lp & 0x40000000) {Inputs.keyDownEvent(wp);}break;case WM_SYSKEYUP:case WM_KEYUP:Inputs.keyUpEvent(wp);break;case WM_CHAR:// 输入字符 char = wpbreak;/************* MOUSE MESSAGES ****************/case WM_MOUSEWHEEL:Inputs.mouseWheelEvent(GET_WHEEL_DELTA_WPARAM(wp) / WHEEL_DELTA);break;case WM_MOUSEMOVE:Inputs.mouseMoveEvent(LOWORDINT(lp), HIWORDINT(lp));break;case WM_LBUTTONDOWN:case WM_LBUTTONDBLCLK:SetFocus(hWnd);Inputs.mouseKeyDownEvent(LOWORDINT(lp), HIWORDINT(lp), VK_LBUTTON);break;case WM_RBUTTONDOWN:case WM_RBUTTONDBLCLK:SetFocus(hWnd);Inputs.mouseKeyDownEvent(LOWORDINT(lp), HIWORDINT(lp), VK_RBUTTON);break;case WM_MBUTTONDOWN:case WM_MBUTTONDBLCLK:SetFocus(hWnd);Inputs.mouseKeyDownEvent(LOWORDINT(lp), HIWORDINT(lp), VK_MBUTTON);break;case WM_LBUTTONUP:Inputs.mouseKeyUpEvent(LOWORDINT(lp), HIWORDINT(lp), VK_LBUTTON);break;case WM_RBUTTONUP:Inputs.mouseKeyUpEvent(LOWORDINT(lp), HIWORDINT(lp), VK_RBUTTON);break;case WM_MBUTTONUP:Inputs.mouseKeyUpEvent(LOWORDINT(lp), HIWORDINT(lp), VK_MBUTTON);break;/************** INPUT MESSAGES 输入消息 **************/default:return DefWindowProc(hWnd, msg, wp, lp);}#undef LOWORDINT
#undef HIWORDINTreturn 0;}// 窗口创建核心函数(古神的召唤仪式)HWND createWindow(int x, int y, int w, int h, LPCWSTR windowName,HINSTANCE hInst, WNDPROC wndProc, LPVOID createLongParam = nullptr) {// 1. 注册窗口类WNDCLASS wc = {0};wc.lpfnWndProc = wndProc;        // 窗口过程函数wc.hInstance = hInst;            // 程序实例wc.lpszClassName = wndClassName; // 窗口类名wc.hCursor = LoadCursor(nullptr, IDC_ARROW); // 默认光标(补充原文缺失)wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 背景色(补充原文缺失)if (!RegisterClass(&wc)) {DWORD err = GetLastError();if (err != ERROR_CLASS_ALREADY_EXISTS) { // 忽略重复注册throw std::runtime_error("窗口类注册失败,错误码:" + std::to_string(err));}}// 2. 创建窗口HWND hWnd = CreateWindow(wndClassName,    // 窗口类名windowName,      // 窗口标题WS_OVERLAPPEDWINDOW, // 窗口风格(修正原文WS_TILEDWINDOW)x, y, w, h,      // 位置和尺寸nullptr,         // 父窗口nullptr,         // 菜单hInst,           // 程序实例createLongParam  // 创建参数(传递this指针));if (!hWnd) {throw std::runtime_error("窗口创建失败,错误码:" + std::to_string(GetLastError()));}return hWnd;}public:// 构造函数:创建窗口(献祭灵魂)my_Win32Window() {hInst = GetModuleHandle(nullptr); // 获取当前程序实例try {// 传入this作为创建参数(灵魂献祭)hWnd = createWindow(x, y, w, h, windowName, hInst, wndProc, this);} catch (const std::runtime_error& e) {MessageBox(nullptr, LPCWSTR(e.what()), L"错误", MB_ICONERROR);}}// 析构函数:释放资源~my_Win32Window() {if (hWnd) {DestroyWindow(hWnd);hWnd = nullptr;}// 取消光标限制if (cursorConfine) {ClipCursor(nullptr);}}example_callbacks Callbacks; // 一些窗口动作的回调example_easyInput Inputs; // 输入处理器// ========== 窗口操作接口 ==========// 显示窗口void Show() {if (hWnd) ShowWindow(hWnd, SW_SHOWDEFAULT);}// 隐藏窗口void Hide() {if (hWnd) ShowWindow(hWnd, SW_HIDE);}// 设置窗口标题void SetTitle(const std::wstring& newTitle) {if (hWnd) SetWindowText(hWnd, newTitle.c_str());}// 获取窗口标题std::wstring GetTitle() {if (!hWnd) return L"";int titleLength = GetWindowTextLength(hWnd);if (titleLength == 0) {DWORD err = GetLastError();if (err != ERROR_SUCCESS) {throw std::runtime_error("获取标题长度失败,错误码:" + std::to_string(err));}return L"";}std::wstring title(titleLength + 1, L'\0');int copiedLength = GetWindowText(hWnd, &title[0], titleLength + 1);if (copiedLength == 0) {DWORD err = GetLastError();if (err != ERROR_SUCCESS) {throw std::runtime_error("获取标题内容失败,错误码:" + std::to_string(err));}return L"";}title.resize(copiedLength);return title;}// 设置窗口图标(从文件加载)void SetIcon(const std::wstring& iconPath) { return; }// 设置窗口位置和尺寸void SetPosAndSize(int newX, int newY, int newW, int newH) {if (hWnd) {SetWindowPos(hWnd, nullptr, newX, newY, newW, newH, SWP_NOZORDER | SWP_FRAMECHANGED);x = newX; y = newY; w = newW; h = newH; // 更新内部属性}}// 获取窗口位置和尺寸void GetPosAndSize(int& outX, int& outY, int& outW, int& outH) {if (!hWnd) return;RECT rect;GetWindowRect(hWnd, &rect);outX = rect.left;outY = rect.top;outW = rect.right - rect.left;outH = rect.bottom - rect.top;}// 设置光标位置(窗口客户区坐标)void SetMousePos(int clientX, int clientY) {if (!hWnd) return;POINT p = {clientX, clientY};ClientToScreen(hWnd, &p); // 转换为屏幕坐标SetCursorPos(p.x, p.y);}// 获取光标位置(窗口客户区坐标)void GetMousePos(int& outX, int& outY) {if (!hWnd) return;POINT p;GetCursorPos(&p); // 获取屏幕坐标ScreenToClient(hWnd, &p); // 转换为客户区坐标outX = p.x;outY = p.y;}// 限制/释放光标在窗口内void ConfineCursor(bool isConfine) {cursorConfine = isConfine;if (!hWnd) return;if (isConfine) {RECT rect;GetClientRect(hWnd, &rect);MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rect), 2);ClipCursor(&rect);} else {ClipCursor(nullptr);}}// 消息循环(窗口运行核心)int MainLoop() {MSG msg = {0};// 处理消息队列while (GetMessage(&msg, nullptr, 0, 0)) {TranslateMessage(&msg); // 翻译键盘消息DispatchMessage(&msg);  // 分发消息到窗口过程}return static_cast<int>(msg.wParam); // 返回退出码}};// 程序入口(WinMain)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {try {// 创建窗口实例(创世)my_Win32Window window;// 显示窗口(唤醒)window.Show();// 设置测试标题window.SetTitle(L"我的Win32窗户 - 已注入灵魂");// 运行消息循环(永生)return window.MainLoop();} catch (const std::exception& e) {MessageBox(nullptr, LPCWSTR(e.what()), L"程序异常", MB_ICONERROR);return -1;}
}
http://www.jsqmd.com/news/458444/

相关文章:

  • 2026年3月重庆主城区土建品牌实力排行榜 - 十大品牌榜
  • Jlink读取MCU固件全流程详解(附常见问题解决方案)
  • ElementUI el-autocomplete清除后下拉框不显示?两种实用修复方案对比
  • 精准掌控酸碱度:2026年酸度计口碑品牌盘点与选购指南 - 品牌推荐大师
  • 孩子脾虚怎么办?2026年3月益气健脾滋补品品牌实力排行榜 - 十大品牌榜
  • AD信号等长规则设置方式-信号线
  • aconda pyqt5安装 - MKT
  • 【芯片书籍推荐之Static timing analysis for nanometer designs a practical approach:芯片工程师timing圣经】
  • Tcl数组与字典的实战对比:何时用数组?何时用字典?
  • Typescript
  • WPS Office 2022最新版:手把手教你插入数学符号(含字母头顶小尖儿详细教程)
  • 手把手教你用二极管搭建简易与门电路(附实测数据)
  • 孩子脾虚怎么办?2026年3月益气健脾保健品实力品牌排行榜 - 十大品牌榜
  • 数据处理相关毕设效率提升实战:从单线程脚本到并发流水线的架构演进
  • 大学生必备APP清单|学习+生活+自律,一键解锁高效校园生活 - 品牌测评鉴赏家
  • 用Python模拟BACnet与Modbus TCP协议转换:从数据映射到通信测试完整实验
  • A100服务器部署img2img-turbo避坑指南:从环境配置到昼夜转换实战
  • MoeCTF2025 Web全解:从入门到实战的完整通关指南
  • 2026年容易消化好吸收的奶粉推荐:五款舒适配方产品评测 - 科技焦点
  • 2026年金融科技哪家好:AI能力与服务深度解析 - 科技焦点
  • 高校选课系统实战:用openGauss+Visio设计强实体/弱实体关系模型
  • 10.Blender曲线修改器/蒙皮修改器
  • Cursor Pro功能完整解锁技术突破方案:从原理到实践的全面指南
  • 哪个GEO公司效果好?业内人士的推荐清单与选择建议 - 品牌推荐大师1
  • Flutter 组件 lemmatizerx 适配鸿蒙 HarmonyOS 实战:端侧词元解析引擎,构建多语言形态学还原的中枢底座
  • 毕业设计实战:基于 Web 的便利店销售管理系统设计与实现(含架构选型与避坑指南)
  • 2026年全国悬浮地板生产厂合作案例多排名,利初塑料制品名列前茅 - 工业推荐榜
  • 突破散热瓶颈:OmenSuperHub开源工具革新惠普游戏本性能释放效率85%
  • 微软 Copilot Cowork 技术拆解:为什么 Claude 成了 Agent 的核心? - 147API
  • 四季南山婴幼儿奶粉评价好吗,看看2026年它在全国奶粉市场的表现 - mypinpai